Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La solución orientada a servicios usa Enterprise Single Sign-On (SSO) tanto para almacenar valores de configuración como para controlar las credenciales de los sistemas back-end. Para reducir la latencia, la solución usa una caché local para los valores de configuración. La solución actualiza la memoria caché cada cinco minutos.
En muchas aplicaciones, los adaptadores controlan las operaciones de SSO, incluida la obtención de un vale de SSO, el canje del vale y el uso de las credenciales para obtener acceso a la aplicación afiliada. Sin embargo, la versión en línea de la solución orientada a servicios no usa adaptadores. Debe usar SSO (inicio de sesión único) desde el código.
En este tema se describe el mecanismo de almacenamiento en caché que usa la solución, así como cómo la versión en línea de la solución usa SSO en el código.
Almacenamiento en caché local de valores de configuración
La solución orientada a servicios usa dos objetos, ConfigPropertyBag y ConfigParameters, para controlar los valores de configuración. La clase ConfigPropertyBag contiene los valores y solo la usa la clase ConfigParameters . La clase ConfigParameters la usan las otras partes de la solución para recuperar los parámetros de configuración. Ambas clases están en el espacio de nombres Microsoft.Samples.BizTalk.WoodgroveBank.ConfigHelper .
Nota:
La solución Orientada a servicios corrige el intervalo de actualización de caché en 300 segundos (5 minutos). En su lugar, puede hacer que el intervalo de actualización de caché sea una propiedad configurable en esta solución. Esto se hace en la solución Administración de procesos empresariales. Para obtener más información sobre cómo esa solución maneja el inicio de sesión único (SSO), consulte Uso eficaz del inicio de sesión único en la solución de gestión de procesos empresariales. Tenga en cuenta que, en tal caso, un cambio en el intervalo de actualización no surte efecto hasta que la memoria caché se actualice al final del tiempo del intervalo anterior.
ConfigPropertyBag tiene los métodos siguientes:
| Método | Descripción |
|---|---|
| Lectura | Recupera un valor para una propiedad determinada. |
| Escribir | Asigna un valor a una propiedad . |
La clase usa una instancia de nameValueCollection de .NET para contener los valores. Los dos métodos de acceso implementan la interfaz IPropertyBag desde el espacio de nombres Microsoft.BizTalk.SSOClient.Interop . La clase ConfigPropertyBag es una clase interna y solo la usa la clase ConfigParameters .
Nota:
Los nombres de clave del contenedor de propiedades no distinguen mayúsculas de minúsculas. NameValueCollection subyacente utiliza un hash insensible a mayúsculas y minúsculas y comparaciones sin distinción entre ellas.
La aplicación usa la clase ConfigParameters para controlar los valores de configuración de SSO. La clase tiene los siguientes métodos y atributos públicos:
| Método o atributo | Descripción |
|---|---|
| SSOConfigParameter | Enumeración para especificar parámetros de configuración. |
| ObtenerParametrosDeConfiguración | Método usado para recuperar un valor para un parámetro determinado. Usa SSOConfigParameter para indicar el parámetro . |
La clase ConfigParameters usa la clase Timer de .NET y una función de delegado para configurar la actualización de ConfigPropertyBag:
private static Timer cacheRefreshTimer;
private static ISSOConfigStore ssoConfigStore;
private static ReaderWriterLock syncLock;
// Cache refresh interval in milliseconds
private const int CacheRefreshInterval = 5 * 60 * 1000;
private static ConfigPropertyBag ssoPropBag;
static ConfigParameters()
{
ssoConfigStore = new ISSOConfigStore();
ssoPropBag = new ConfigPropertyBag();
syncLock = new ReaderWriterLock();
ssoConfigStore.GetConfigInfo(SSO_CONFIG_APP,
SSO_IDENTIFIER_NAME, SSOFlag.SSO_FLAG_RUNTIME,
ssoPropBag);
cacheRefreshTimer = new Timer(
new TimerCallback(ConfigParameters.cacheRefreshCallback),
null, CacheRefreshInterval, CacheRefreshInterval);
}
Observe que el constructor estático inicializa las variables de miembro estáticas, lo que permite el uso de métodos de clase sin crear una instancia de la clase . El constructor crea instancias del almacén de configuración de SSO (ISSOConfigStore), el contenedor de propiedades de configuración (ConfigPropertyBag) y un bloqueo de sincronización (ReaderWriterLock) que se usa para controlar el acceso a ConfigurationPropertyBag durante las actualizaciones y lecturas. A continuación, el constructor usa GetConfigInfo para recuperar los valores de configuración de SSO y colocarlos en el contenedor de propiedades. Por último, el constructor crea un objeto Timer que, después del intervalo especificado, llama a la función delegate, cacheRefreshCallback.
La función delegada Timer es relativamente sencilla.
private static void cacheRefreshCallback(object state)
{
// Disable the timer until we are done loading the cache.
cacheRefreshTimer.Change(Timeout.Infinite, CacheRefreshInterval);
// Put the data from SSO in a new property bag so that
// we don't have to lock the property bag and block it from being
// used. The SSO call is a remote call and may take a while.
ConfigPropertyBag propBag2 = new ConfigPropertyBag();
ssoConfigStore.GetConfigInfo(SSO_CONFIG_APP,
SSO_IDENTIFIER_NAME, SSOFlag.SSO_FLAG_RUNTIME, propBag2);
// Get a writer lock before updating the cached values.
syncLock.AcquireWriterLock(Timeout.Infinite);
try
{
ssoPropBag = propBag2;
}
finally
{
syncLock.ReleaseWriterLock();
}
// Enable the timer.
cacheRefreshTimer.Change(CacheRefreshInterval,
CacheRefreshInterval);
}
Observe que el método de devolución de llamada de actualización de caché deshabilita el temporizador para que el método pueda ejecutarse de principio a fin. Observe también el uso de los bloqueos para controlar el acceso al contenedor de propiedades. ReaderWriterLock es la mejor opción aquí: está diseñado para casos en los que hay más lecturas que escrituras. Observe también que el bloqueo, syncLock, es estático y se declara en el nivel de clase que todos los subprocesos comparten la misma instancia única de él.
Uso del inicio de sesión único desde Code
Al usar el inicio de sesión único desde el código, el código debe asumir el rol del adaptador, es decir, recuperar el vale de inicio de sesión único del mensaje, canjear el vale para obtener el nombre de usuario y la contraseña del sistema de fondo, y, por último, usar el sistema de fondo. La solución orientada a servicios lo hace a través del método GetPendingTransactionsResponse del objeto PendingTransactionsCaller .
El método aparece de la siguiente manera:
public static PendingTransactionsResponse GetPendingTransactionsResponse(XLANGMessage requestMsg)
{
try
{
// Get config parameter values.
int ptTimeout = Convert.ToInt32(
ConfigParameters.GetConfigParameter(
ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_INLINE_TIMEOUT
)
);
string ptURL = ConfigParameters.GetConfigParameter(
ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_URL
);
string ssoAffliateApp = ConfigParameters.
GetConfigParameter(ConfigParameters.
SSOConfigParameter.
PENDING_TRANSACTIONS_SSO_AFFILIATE_APP
);
// Redeem the SSO ticket and get the userid/password to
// use to interact with Pending Transaction System.
// Extract the ticket…
string msgTicket = (string)requestMsg.
GetPropertyValue(typeof(BTS.SSOTicket));
// and the user name of the originating user.
string originatorSID = (string)requestMsg.
GetPropertyValue(
typeof(
Microsoft.BizTalk.XLANGs.BTXEngine.OriginatorSID
)
);
string pendTransUserName;
// Now, redeem the ticket.
string[] pendTransCredential =
ssoTicket.RedeemTicket(
ssoAffliateApp,
originatorSID,
msgTicket,
SSOFlag.SSO_FLAG_NONE,
out pendTransUserName
);
PendingTransactionsRequest req =
(PendingTransactionsRequest)requestMsg[0].
RetrieveAs(
typeof(PendingTransactionsRequest)
);
PendingTransactionsResponse resp;
using (PendingTransactionsWebService
svc = new PendingTransactionsWebService())
{
svc.Url = ptURL;
svc.Timeout = ptTimeout;
// The web service uses basic authentication, so we
//need to send the user id and password in the request.
CredentialCache credCache = new CredentialCache();
NetworkCredential credentialToUse =
new NetworkCredential(
pendTransUserName, pendTransCredential[0]
);
credCache.Add(new Uri(svc.Url), "Basic", credentialToUse);
svc.Credentials = credCache;
resp = svc.GetPendingTransactions(req);
}
return resp;
}
catch (System.Net.WebException webEx)
{
if (webEx.Status == WebExceptionStatus.Timeout)
{
throw new PendingTransactionsTimeoutException();
}
else
{
Trace.WriteLine("Other Net.WebException: "
+ webEx.ToString()
+ (null == webEx.InnerException ? "" :
("Inner Exception: "
+ webEx.InnerException.ToString())
)
);
throw;
}
}
catch(System.Exception ex)
{
Trace.WriteLine("Other Exception: "
+ ex.ToString()
+ (null == ex.InnerException ? "" :
("Inner Exception: "
+ ex.InnerException.ToString())
)
);
throw;
}
}
El método comienza recuperando información de configuración, incluida la dirección URL, para el sistema back-end y el nombre de la aplicación back-end (afiliada).
Para canjear el billete, el método debe extraer el billete y el nombre de usuario original que solicita. El mensaje contiene el ticket como una de las propiedades de contexto del mensaje, BTS.SSOTicket. Para obtener más información, consulte Propiedades de contexto de mensaje en la guía de Interfaz de Usuario y referencia del espacio de nombres de API de desarrolladores. El método también extrae el OriginorSID de las propiedades de contexto del mensaje. Con el ticket y el nombre del originador en mano, el método llama al método RedeemTicket del ticket para recuperar las credenciales.
El resto del código crea una memoria caché de .NET NetworkCredential para las credenciales y llama al servicio web back-end.
Nota:
Dado que el nombre de usuario y la contraseña regresan del inicio de sesión único en texto claro, quiere minimizar la vida de las variables que contienen esa información. Observe que el código declara las variables de credencial dentro de un bloque try . Aquí, las variables expiran al salir del bloque try .
Véase también
Aspectos destacados de la implementación de la solución orientada a servicios