Acceder al servicio PerSession simultáneamente en WCF usando C#
wcf-binding wcf-client (2)
1.) Tengo un método principal de procesamiento, que toma cadena como un argumento y esa cadena contiene algunas x número de tareas.
2.) Tengo otro método Status, que realiza un seguimiento del primer método mediante el uso de dos variables TotalTests y CurrentTest. que se modificará cada vez con un bucle en el primer método (Procesamiento).
3.) Cuando más de un cliente realiza una llamada de forma paralela a mi servicio web para llamar al método de procesamiento pasando una cadena, que tiene diferentes tareas llevará más tiempo en procesarse. así que, mientras tanto, los clientes usarán un segundo hilo para llamar al método Estado en el servicio web para obtener el estado del primer método.
4.) cuando se realiza el punto número 3, todos los clientes deben obtener las variables (TotalTests, CurrentTest) de forma paralela sin mezclarse con otras solicitudes de los clientes.
5.) El código que he proporcionado a continuación es obtener resultados de variables mezcladas para todos los clientes cuando los hago como estáticos. Si elimino estática para las variables, entonces los clientes solo obtienen todos los 0 para estas 2 variables y no puedo solucionarlo. Por favor, eche un vistazo al código a continuación.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{
public int TotalTests = 0;
public int CurrentTest = 0;
public string Processing(string OriginalXmlString)
{
XmlDocument XmlDoc = new XmlDocument();
XmlDoc.LoadXml(OriginalXmlString);
this.TotalTests = XmlDoc.GetElementsByTagName("TestScenario").Count; //finding the count of total test scenarios in the given xml string
this.CurrentTest = 0;
while(i<10)
{
++this.CurrentTest;
i++;
}
}
public string Status()
{
return (this.TotalTests + ";" + this.CurrentTest);
}
}
configuración del servidor
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="true" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
configuración del cliente
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="true" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
A continuación se menciona mi código de cliente
class Program
{
static void Main(string[] args)
{
Program prog = new Program();
Thread JavaClientCallThread = new Thread(new ThreadStart(prog.ClientCallThreadRun));
Thread JavaStatusCallThread = new Thread(new ThreadStart(prog.StatusCallThreadRun));
JavaClientCallThread.Start();
JavaStatusCallThread.Start();
}
public void ClientCallThreadRun()
{
XmlDocument doc = new XmlDocument();
doc.Load(@"D:/t72CalculateReasonableWithdrawal_Input.xml");
bool error = false;
Service1Client Client = new Service1Client();
string temp = Client.Processing(doc.OuterXml, ref error);
}
public void StatusCallThreadRun()
{
int i = 0;
Service1Client Client = new Service1Client();
string temp;
while (i < 10)
{
temp = Client.Status();
Thread.Sleep(1500);
Console.WriteLine("TotalTestScenarios;CurrentTestCase = {0}", temp);
i++;
}
}
}
Alguien puede ayudarme porfavor.
Primero, porque necesita acceder al servicio simultáneamente, cuando el servicio está procesando la primera llamada del cliente (Procesamiento), debe cambiar el modo de concurrencia del servicio a Múltiple.
También desea mantener el estado de procesamiento de cada cliente, por lo que debe establecer el modo de contexto de la instancia en PerSession.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode= InstanceContextMode.PerSession)]
Nota
- El InstanceContextMode predeterminado es PerSession
- El modo de Concurrencia predeterminado es único
Puede hacer lo siguiente para asegurarse de que su configuración sea compatible con PerSession InstanceContextMode. Con este método, WCF emitirá una excepción de tiempo de ejecución si es necesario.
[ServiceContract(SessionMode=SessionMode.Required)]
Nota Con InstanceContextMode.PerSession obtendrás diferentes instancias por cada proxy que crees
Por lo tanto, solo necesita una instancia de "Cliente de servicio 1" por cliente, que llamará a su método de Proceso y también recuperará el estado.
También para el procesamiento pesado virtual, puede usar Thread.Sleep (milisegundos) para propuestas de prueba solo en el método "Processing" (Servicio).
Para la aplicación cliente, si desea llamar al método "Procesamiento" y luego usar el método Estado para recuperar el estado, debe llamar al Método de proceso de forma asíncrona.
1. Haga clic derecho en la referencia de servicio en el explorador de soluciones y seleccione "Configurar referencia de servicio", luego marque la casilla "Generar operación asíncrona" y presione OK.
2. Cambie su código de cliente como este
static void Main(string[] args)
{
StartProcessing();
StatusReport();
Console.ReadLine();
}
static ServiceClient Client = new ServiceClient();
private static bool Completed = false;
public static void StartProcessing()
{
XmlDocument doc = new XmlDocument();
doc.Load(@"D:/t72CalculateReasonableWithdrawal_Input.xml");
bool error = false;
Client.ProcessingCompleted += Client_ProcessingCompleted;
Client.ProcessingAsync(doc.OuterXml);
Console.WriteLine("Processing...");
}
static void Client_ProcessingCompleted(object sender, ProcessingCompletedEventArgs e)
{
// processing is completed, retreive the return value of Processing operation
Completed = true;
Console.WriteLine(e.Result);
}
public static void StatusReport()
{
int i = 0;
string temp;
while (!Completed)
{
temp = Client.Status();
Console.WriteLine("TotalTestScenarios;CurrentTestCase = {0}", temp);
Thread.Sleep(500);
i++;
}
}
PerSession
no hará que sus variables estáticas no se compartan entre las instancias de objetos. Lo único que PerSession
modo de contexto PerSession
es controlar la duración del objeto.
Con PerSession
WCF no destruye el objeto de servicio hasta que finaliza la sesión. La sesión puede cerrarse explícitamente por cliente o por tiempo de espera (el valor predeterminado es 10 min). Cada llamada siguiente del cliente con la misma ID de sesión será enrutada por WCF a un objeto existente.
Las variables no deben ser estáticas para evitar que se compartan entre diferentes instancias de servicio. El estado de las variables será mantenido por WCF siempre que use InstanceContextMode.PerSession
y el enlace que mantenga la sesión.
public int TotalTests = 0;
public int CurrentTest = 0;
También agregaría SessionMode.Required
to contract para asegurarme de que el servicio esté configurado correctamente.
[ServiceContract(SessionMode = SessionMode.Required )]