Ejemplo de Hola a todos preparado
El ejemplo Hello World Ready muestra las operaciones básicas relacionadas con la creación, implementación y prueba de un procedimiento almacenado de integración con CLR (Common Language Runtime) simple internacionalizado. Un componente internacionalizado se puede localizar fácilmente a distintos idiomas para diferentes mercados del mundo entero sin cambiar el código fuente del componente. Este ejemplo también muestra cómo devolver datos al cliente a través de un parámetro de salida y a través de un registro que el procedimiento almacenado crea dinámicamente. Este ejemplo es casi idéntico al descrito en Hello World, salvo que es mucho más fácil y seguro localizar esta aplicación. Para cambiar el texto localizado se requiere lo siguiente:
Cambiar un archivo XML (el archivo .resx) correspondiente a la referencia cultural concreta en el directorio de recursos.
Generar el archivo de recursos de la referencia cultural con resgen.
Generar el archivo DLL satélite actualizado para esa referencia cultural.
Quitar y agregar ese ensamblado en SQL Server
El código fuente y el ensamblado para el procedimiento almacenado de CLR en sí no cambian. Se proporciona un script build.cmd que muestra cómo compilar y vincular los ensamblados de recursos. Aunque el código fuente de la aplicación crea un administrador de recursos basado en el ensamblado que se ejecuta en el momento, no es necesario incrustar los recursos que no dependen de la referencia cultural en el archivo DLL que contiene el procedimiento almacenado. El System.Resources.NeutralResourcesLanguage attribute permite que los recursos que no dependen de una referencia cultural existan en un archivo DLL satélite. Es mucho mejor usar un archivo DLL independiente con este fin, de modo que, cuando deba agregarse o cambiarse un texto localizado, no sea necesario cambiar el archivo DLL principal que contiene el procedimiento almacenado CLR. Esto resulta especialmente útil para tipos CLR definidos por el usuario que podrían tener columnas y otras dependencias que dificultarían la acción de quitar y volver a agregar el tipo. Normalmente, las versiones de archivo DLL satélite deben ser idénticas a la versión del ensamblado principal. Sin embargo, se puede usar el atributo SatelliteContractVersion para permitir la actualización del ensamblado principal sin actualizar también los ensamblados satélite. Para obtener más información, vea la clase ResourceManager en la documentación de Microsoft .NET.
Requisitos previos
Este ejemplo solo funciona con SQL Server 2005 y versiones posteriores.
Para crear y ejecutar este proyecto se debe instalar el siguiente software:
SQL Server o SQL Server Express. Puede obtener SQL Server Express de forma gratuita desde el sitio web de documentación y ejemplos de SQL Server Express.
La base de datos AdventureWorks que está disponible en el sitio web para desarrolladores de SQL Server.
.NET Framework SDK 2.0 o posterior, o Microsoft Visual Studio 2005 o posterior. Puede obtener .NET Framework SDK de forma gratuita.
Además, se deben cumplir las siguientes condiciones:
La instancia de SQL Server que está utilizando debe tener habilitada la integración con CLR.
Para habilitar la integración con CLR, siga estos pasos:
Habilitar la integración CLR
- Ejecute los siguientes comandos Transact-SQL:
sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO
[!NOTA]
Para habilitar CLR, debe tener el permiso de nivel de servidor ALTER SETTINGS, que se concede implícitamente a los miembros de los roles fijos de servidor sysadmin y serveradmin.
La base de datos de AdventureWorks debe estar instalada en la instancia de SQL Server que está utilizando.
Si no es administrador de la instancia de SQL Server que utiliza, debe hacer que un administrador le conceda el permiso CreateAssembly para completar la instalación.
Generar el ejemplo
Cree y ejecute el ejemplo utilizando las siguientes instrucciones:
Abra un símbolo del sistema de Visual Studio o de .NET Framework.
Si es necesario, cree un directorio para el ejemplo. Para este ejemplo, utilizaremos C:\MySample.
En c:\MySample, cree HelloWorld.vb (para el ejemplo de Visual Basic) o HelloWorld.cs (para el ejemplo de C#) y copie el código muestra de Visual Basic o de C# que corresponda (más abajo) en el archivo.
En c:\MySample, cree el archivo messages.resx y copie el código muestra en el archivo.
En c:\MySample, cree el archivo messages.de.resx guardando el archivo messages.resx como messages.de.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve">Hallo Welt!</value>
En c:\MySample, cree el archivo messages.es.resx guardando el archivo messages.resx como messages.es.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve">Hola a todos</value>
En c:\MySample, cree el archivo messages.fr.resx guardando el archivo messages.resx como messages.fr.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve">Bonjour !</value>
En c:\MySample, cree el archivo messages.fr-FR.resx guardando el archivo messages.resx como messages.fr-FR.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve">Bonjour de France!</value>
En c:\MySample, cree el archivo messages.it.resx guardando el archivo messages.resx como messages.it.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve">Buongiorno</value>
En c:\MySample, cree el archivo messages.ja.resx guardando el archivo messages.resx como messages.ja.resx después de cambiar la línea
<value xml:space="preserve">Hello, World!</value>
para que se lea
<value xml:space="preserve"> ã?“ã‚“ã?«ã?¡ã?¯</value>
En c:\MySample, cree el archivo build.com y copie el código muestra en el archivo.
Compile los ensamblados satélite ejecutando la compilación de archivo en el símbolo del sistema.
Compile el código muestra desde el símbolo del sistema ejecutando uno de los comandos siguientes:
Vbc /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll,C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll,C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll /out:HelloWorldReady.dll /target:library HelloWorld.vb
Csc /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.XML.dll /out:HelloWorldReady.dll /target:library Hello.csCopy the tsql installation code into a file and save it as Install.sql in the sample directory.
Si el ejemplo está instalado en un directorio distinto de C:\MySample\, edite el archivo Install.sql del archivo como se indica para señalar esa ubicación.
Implemente el ensamblado y el procedimiento almacenado ejecutando
- sqlcmd -E -I -i install.sql
Copie el script de comandos de prueba de Transact-SQL en un archivo y guárdelo como test.sql en el directorio del ejemplo.
Ejecute el script de prueba con el siguiente comando
- sqlcmd -E -I -i test.sql
Copie el script de Transact-SQL limpio en un archivo y guárdelo como cleanup.sql en el directorio de ejemplo.
Ejecute el script con el siguiente comando
- sqlcmd -E -I -i cleanup.sql
Código muestra
A continuación se muestra el código de este ejemplo.
C#
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Globalization;
using System.Threading;
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: System.Resources.NeutralResourcesLanguage("", System.Resources.UltimateResourceFallbackLocation.Satellite)]
[assembly: System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.RequestMinimum)]
[assembly: System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.MayCorruptInstance, System.Runtime.ConstrainedExecution.Cer.None)]
public sealed partial class StoredProcedures
{
private StoredProcedures()
{
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters"), Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloWorldReady(string culture, out string greeting)
{
ResourceManager rm
= new ResourceManager("Messages",
Assembly.GetExecutingAssembly());
string message = rm.GetString("HelloWorld", CultureInfo.GetCultureInfo(culture));
Microsoft.SqlServer.Server.SqlMetaData columnInfo
= new Microsoft.SqlServer.Server.SqlMetaData("Column1", SqlDbType.NVarChar, 24);
SqlDataRecord greetingRecord
= new SqlDataRecord(new Microsoft.SqlServer.Server.SqlMetaData[] { columnInfo });
greetingRecord.SetString(0, message);
SqlContext.Pipe.Send(greetingRecord);
greeting = message;
}
}
Visual Basic
Imports System
Imports System.Data
Imports System.Data.Sql
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Globalization
Imports System.Resources
Imports System.Reflection
Imports System.Runtime.InteropServices
<Assembly: AssemblyVersion("1.0.*")>
<Assembly: System.Runtime.InteropServices.ComVisible(False)>
<Assembly: System.CLSCompliant(True)>
<Assembly: System.Resources.NeutralResourcesLanguage("", System.Resources.UltimateResourceFallbackLocation.Satellite)>
<Assembly: System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.RequestMinimum)>
<Assembly: System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, Runtime.ConstrainedExecution.Cer.None)>
Partial Public NotInheritable Class StoredProcedures
Private Sub New()
End Sub
<Microsoft.SqlServer.Server.SqlProcedure()> _
Public Shared Sub HelloWorldReady(ByVal culture As String, ByRef greeting As String)
Dim rm As New ResourceManager("Messages", Assembly.GetExecutingAssembly())
Dim message As String = rm.GetString("HelloWorld", CultureInfo.GetCultureInfo(culture))
Dim columnInfo As New Microsoft.SqlServer.Server.SqlMetaData("Column1", _
SqlDbType.NVarChar, 24)
Dim greetingRecord As New SqlDataRecord(New _
Microsoft.SqlServer.Server.SqlMetaData() {columnInfo})
greetingRecord.SetString(0, message)
SqlContext.Pipe.Send(greetingRecord)
greeting = message
End Sub
End Class
Este es el script build.com que compila los ensamblados satélite.
resgen Messages.resx
resgen Messages.de.resx
resgen Messages.es.resx
resgen Messages.fr.resx
resgen Messages.fr-Fr.resx
resgen Messages.it.resx
resgen Messages.ja.resx
if not exist de/ mkdir de
if not exist es/ mkdir es
if not exist fr/ mkdir fr
if not exist fr-FR/ mkdir fr-FR
if not exist it/ mkdir it
if not exist ja/ mkdir ja
al /t:lib /culture:de /embed:Messages.de.resources /out:de\HelloWorldReady.resources.dll
al /t:lib /culture:es /embed:Messages.es.resources /out:es\HelloWorldReady.resources.dll
al /t:lib /culture:fr /embed:Messages.fr.resources /out:fr\HelloWorldReady.resources.dll
al /t:lib /culture:fr-FR /embed:Messages.fr-FR.resources /out:fr-FR\HelloWorldReady.resources.dll
al /t:lib /culture:it /embed:Messages.it.resources /out:it\HelloWorldReady.resources.dll
al /t:lib /culture:ja /embed:Messages.ja.resources /out:ja\HelloWorldReady.resources.dll
al /t:lib /culture:"" /embed:Messages.resources /out:HelloWorldReady.resources.dll
Este es el script de instalación de Transact-SQL (Install.sql), que implementa los ensamblados y crea el procedimiento almacenado en la base de datos.
USE AdventureWorks
GO
-- Drop existing sproc and assembly if any.
IF EXISTS (SELECT * FROM sys.procedures WHERE [name] = 'usp_HelloWorldReady')
DROP PROCEDURE usp_HelloWorldReady;
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady')
DROP ASSEMBLY HelloWorldReady;
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.neutral')
DROP ASSEMBLY [HelloWorldReady.resources.neutral]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.de')
DROP ASSEMBLY [HelloWorldReady.resources.de]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.es')
DROP ASSEMBLY [HelloWorldReady.resources.es]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.fr')
DROP ASSEMBLY [HelloWorldReady.resources.fr]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.fr-FR')
DROP ASSEMBLY [HelloWorldReady.resources.fr-FR]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.it')
DROP ASSEMBLY [HelloWorldReady.resources.it]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.ja')
DROP ASSEMBLY [HelloWorldReady.resources.ja]
GO
DECLARE @SamplesPath nvarchar(1024)
-- You may need to modify the value of this variable if you have installed the sample someplace other than the default location.
Set @SamplesPath = N'C:\MySample\'
-- Add the assembly and CLR integration based stored procedure
CREATE ASSEMBLY HelloWorldReady
FROM @SamplesPath + 'HelloWorldReady.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.neutral]
FROM @SamplesPath + 'HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.de]
FROM @SamplesPath + '\de\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.es]
FROM @SamplesPath + '\es\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.fr]
FROM @SamplesPath + '\fr\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.fr-FR]
FROM @SamplesPath + '\fr-FR\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.it]
FROM @SamplesPath + '\it\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
CREATE ASSEMBLY [HelloWorldReady.resources.ja]
FROM @SamplesPath + '\ja\HelloWorldReady.resources.dll'
WITH permission_set = Safe;
GO
CREATE PROCEDURE usp_HelloWorldReady
(
@Culture NVarchar(12),
@Greeting NVarchar(24) OUTPUT
)
AS EXTERNAL NAME HelloWorldReady.StoredProcedures.HelloWorldReady;
GO
USE master;
GO
Este es el script test.sql que prueba el ejemplo ejecutando las funciones en cada configuración regional.
USE AdventureWorks
GO
DECLARE @GreetingDe nvarchar(24);
DECLARE @GreetingDe_CH nvarchar(24);
DECLARE @GreetingEn nvarchar(24);
DECLARE @GreetingEs nvarchar(24);
DECLARE @GreetingFr nvarchar(24);
DECLARE @GreetingFr_FR nvarchar(24);
DECLARE @GreetingIt nvarchar(24);
DECLARE @GreetingJa nvarchar(24);
--German as spoken anywhere in the world (the neutral German culture)
EXEC usp_HelloWorldReady 'de', @GreetingDe OUTPUT;
--German as spoken in Switzerland. Because we don't have a specific assembly
--for this case, the .NET Framework will automatically fall back to the neutral German culture DLL.
EXEC usp_HelloWorldReady 'de-CH', @GreetingDe_CH OUTPUT;
EXEC usp_HelloWorldReady 'en', @GreetingEn OUTPUT;
EXEC usp_HelloWorldReady 'es', @GreetingEs OUTPUT;
--French as spoken anywhere in the world (the neutral French culture)
EXEC usp_HelloWorldReady 'fr', @GreetingFr OUTPUT
--French as spoken in France. Since we do have a specific assembly for this case, a specific
--greeting is provided from that DLL. The neutral French culture DLL is not used in this case.
EXEC usp_HelloWorldReady 'fr-FR', @GreetingFr_FR OUTPUT
EXEC usp_HelloWorldReady 'it', @GreetingIt OUTPUT;
EXEC usp_HelloWorldReady 'ja', @GreetingJa OUTPUT;
SELECT @GreetingDe AS OUTPUT_PARAMETER_DE;
SELECT @GreetingDe_CH AS OUTPUT_PARAMETER_De_CH;
SELECT @GreetingEn AS OUTPUT_PARAMETER_EN;
SELECT @GreetingEs AS OUTPUT_PARAMETER_ES;
SELECT @GreetingFr AS OUTPUT_PARAMETER_FR;
SELECT @GreetingFr_FR AS OUTPUT_PARAMETER_Fr_FR;
SELECT @GreetingIt AS OUTPUT_PARAMETER_IT;
SELECT @GreetingJa AS OUTPUT_PARAMETER_JA;
GO
El siguiente Transact-SQL quita de la base de datos los ensamblados y el procedimiento almacenado.
USE AdventureWorks;
GO
-- Drop existing sproc and assembly if any.
IF EXISTS (SELECT * FROM sys.procedures WHERE [name] = 'usp_HelloWorldReady')
DROP PROCEDURE usp_HelloWorldReady;
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady')
DROP ASSEMBLY HelloWorldReady;
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.neutral')
DROP ASSEMBLY [HelloWorldReady.resources.neutral]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.de')
DROP ASSEMBLY [HelloWorldReady.resources.de]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.es')
DROP ASSEMBLY [HelloWorldReady.resources.es]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.fr')
DROP ASSEMBLY [HelloWorldReady.resources.fr]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.fr-FR')
DROP ASSEMBLY [HelloWorldReady.resources.fr-FR]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.it')
DROP ASSEMBLY [HelloWorldReady.resources.it]
GO
IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] = 'HelloWorldReady.resources.ja')
DROP ASSEMBLY [HelloWorldReady.resources.ja]
GO
USE master;
GO
Vea también
Conceptos
Escenarios de uso y ejemplos para la integración de Common Language Runtime (CLR)