wcf wsdualhttpbind проблема тайм-аута
Пожалуйста, помогите мне!!!
Я пытаюсь создать приложение, которое использует контракты обратных вызовов. Мое приложение отлично работает как на клиенте, так и на сервере на одном компьютере, но когда я пытаюсь получить доступ к сервису с другого компьютера, я получаю тайм-аут исключения (операция din не завершена в течение выделенное время ожидания). Клиент считывает некоторые значения и выбрасывает службу из базы данных, которая находится на сервере. Я не знаю, где моя ошибка. Я попытался поместить клиента в виртуальную машину, а службу (и базу данных) на реальной машине.
Вот мой файл конфигурации сервера:
<binding name="TrainService" closeTimeout="00:02:00" openTimeout="00:02:00"
receiveTimeout="00:10:00" sendTimeout="00:02:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="None">
<message clientCredentialType="None" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
<wsHttpBinding>
<binding name="WSHttpBinding_ITrainService" closeTimeout="00:02:00"
openTimeout="00:02:00" receiveTimeout="00:10:00" sendTimeout="00:02:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="None" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8732/Design_Time_Addresses/WCFandEFService/TrainService/"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITrainService"
contract="TrainServiceRef.ITrainService" name="WSHttpBinding_ITrainService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:8080/TcpService" binding="netTcpBinding"
contract="TrainServiceRef.ITrainService" name="NetTcpBinding_ITrainService" />
<endpoint address="http://localhost:8082/InterlockingService/Host/line"
binding="wsDualHttpBinding" bindingConfiguration="LineService"
contract="InterlockingServiceReference.ILineService" name="LineService">
<identity>
<userPrincipalName value="Romina-PC\Romina" />
</identity>
</endpoint>
<endpoint address="http://localhost:8082/InterlockingService/Host/trains"
binding="wsDualHttpBinding" bindingConfiguration="TrainService"
contract="InterlockingServiceReference.ITrainService" name="TrainService">
<identity>
<userPrincipalName value="Romina-PC\Romina" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Мой файл конфигурации клиента:
->
<binding name="TrainService" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="52428800" maxReceivedMessageSize="6553600"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="1638400"
maxBytesPerRead="4096" maxNameTableCharCount="1638400" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="None">
<!--<message clientCredentialType="None" negotiateServiceCredential="true"
algorithmSuite="Default" />-->
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8082/InterlockingService/Host/line"
binding="wsDualHttpBinding" bindingConfiguration="LineService"
contract="InterlockingServiceRef.ILineService" name="LineService">
<identity>
<userPrincipalName value="Romina-PC\Romina" />
</identity>
</endpoint>
<endpoint address="http://localhost:8082/InterlockingService/Host/trains"
binding="wsDualHttpBinding" bindingConfiguration="TrainService"
contract="InterlockingServiceRef.ITrainService" name="TrainService">
<identity>
<userPrincipalName value="Romina-PC\Romina" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Спасибо.
Это контракты: открытый интерфейс ITrainServiceCallBack { [OperationContract (IsOneWay=true)] void OnTrainChangeState(TrainData train); }
//[ServiceContract(Name = "LineService", CallbackContract = typeof(ILineServiceCallBack))]
[ServiceContract(CallbackContract = typeof(ITrainServiceCallBack))]
public interface ITrainService
{
[OperationContract]
TrainData GetTrainData(string trainName);
[OperationContract]
bool ChangeTrainState_bool(ref TrainData train);
[OperationContract]
void ChangeTrainState(ref Trains_Detail train);
[OperationContract]
bool SubscribeToTrainChangeEvent();
[OperationContract]
bool UnSubscribeFromTrainChangeEvent();
[OperationContract]
TrainData TranslateTrainEntityToTrainData(Trains_Detail trainEntity);
[OperationContract]
IEnumerable<Trains_Detail> GetTrains();
[OperationContract]
IEnumerable<Trains_Detail> GetTrains_ByStation(int Statie_plecare, int Statie_sosire);
}
Реализация метода:
используя Систему; using System.Collections.Generic; использование System.Linq; использование System.Runtime.Serialization; using System.ServiceModel; использование System.Text; используя System.Data;
namespace WCFandEFService {// ПРИМЕЧАНИЕ. Вы можете использовать команду "Переименовать" в меню "Refactor", чтобы изменить имя класса "ProductService" в коде и файле конфигурации вместе. // [ServiceBehavior (ConcurrencyMode = ConcurrencyMode.Multiple)]
public partial class InterlockingService : ITrainService
{
static List<ITrainServiceCallBack> subscribers_train = new List<ITrainServiceCallBack>();
public bool TrainExists(string nrTren, InterlockingEntities database)
{
// Check to see whether the specified product exists in the database
int numTrain = (from t in database.Trains_Details
where string.Equals(t.Nr_tren, nrTren)
select t).Count();
return numTrain > 0;
}
public TrainData TranslateTrainEntityToTrainData(Trains_Detail trainEntity)
{
TrainData train = new TrainData();
train.nrTren=trainEntity.Nr_tren;
train.ora_Plecare= trainEntity.Ora_plecare;
train.ora_Sosire=trainEntity.Ora_sosire;
train.statie_Plecare=trainEntity.Statie_plecare;
train.statie_Sosire=trainEntity.Statie_sosire;
train.rang=trainEntity.Rang;
train.observatii=trainEntity.Observatii;
train.RowVersion=trainEntity.RowVersion;
return train;
}
#region ILineService Members
public IEnumerable<Trains_Detail> GetTrains()
{
InterlockingEntities context = new InterlockingEntities();
IEnumerable<Trains_Detail> result =
(from t in context.Trains_Details
//where l.Station == station
select t);
return result;
}
public IEnumerable<Trains_Detail> GetTrains_ByStation(int Statie_plecare,int Statie_sosire)
{
InterlockingEntities context = new InterlockingEntities();
IEnumerable<Trains_Detail> result =
(from t in context.Trains_Details
where t.Statie_plecare==Statie_plecare && t.Statie_sosire==Statie_sosire
select t);
return result;
}
public TrainData GetTrainData(string trainNr)
{
InterlockingEntities context = new InterlockingEntities();
Trains_Detail trainInDB =
(from t
in context.Trains_Details
where String.Compare(t.Nr_tren, trainNr) == 0
select t).FirstOrDefault();
if (trainInDB == null)
{
throw new Exception("No line cu numele " + trainInDB.Nr_tren);
}
context.Detach(trainInDB);
return TranslateTrainEntityToTrainData(trainInDB);
}
public bool ChangeTrainState_bool(ref TrainData train)
{
InterlockingEntities context = new InterlockingEntities();
String trainName = train.nrTren;
//int lineStation = line.station;
Trains_Detail trainInDB =
(from t
in context.Trains_Details
where String.Compare(t.Nr_tren, trainName) == 0
select t).FirstOrDefault();
if (trainInDB == null)
{
throw new Exception("No train cu numele " + trainInDB.Nr_tren);
}
context.Detach(trainInDB);
trainInDB.Nr_tren = train.nrTren;
trainInDB.Ora_plecare=train.ora_Plecare;
trainInDB.Ora_sosire=train.ora_Sosire;
trainInDB.Statie_plecare=train.statie_Plecare;
trainInDB.Statie_sosire=train.statie_Sosire;
trainInDB.Rang=train.rang;
trainInDB.RowVersion = train.RowVersion;
context.Attach(trainInDB);
context.ObjectStateManager.ChangeObjectState(trainInDB, System.Data.EntityState.Modified);
context.SaveChanges();
train.RowVersion = trainInDB.RowVersion;
context.Dispose();
raiseTrainChangeState(TranslateTrainEntityToTrainData(trainInDB));
return true;
}
public void ChangeTrainState(ref Trains_Detail train)
{
using (var context = new InterlockingEntities())
{
context.Attach(train);
context.ObjectStateManager.ChangeObjectState(train, EntityState.Modified);
context.SaveChanges();
}
}
}
public bool SubscribeToTrainChangeEvent()
{
try
{
ITrainServiceCallBack callback = OperationContext.Current.GetCallbackChannel<ITrainServiceCallBack>();
if (!subscribers_train.Contains(callback))
{
subscribers_train.Add(callback);
}
return true;
}
catch (Exception)
{
return false;
}
}
public bool UnSubscribeFromTrainChangeEvent()
{
try
{
ITrainServiceCallBack callback = OperationContext.Current.GetCallbackChannel<ITrainServiceCallBack>();
subscribers_train.Remove(callback);
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
private void raiseTrainChangeState(TrainData train)
{
subscribers_train.AsParallel().ForAll(callback =>
{
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
callback.OnTrainChangeState(train);
}
else
{
subscribers_train.Remove(callback);
}
});
}
}
}
3 ответа
Операционный контракт (ы) в контракте обратного вызова должен иметь пометку IsOneWay = true и должен возвращать недействительный - не все контракты на операции в сервисе.
Кроме того, у меня была похожая проблема с использованием дуплексных контрактов через NetTcpBinding. Я решил это, установив значение OperationTimeout на прокси (в моем случае, до 5 минут). Я установил его программно, приведя мой канал к интерфейсу IContextChannel на клиенте при создании канала. Вы, вероятно, сможете сделать то же самое в файле конфигурации клиента.
Мой код:
((IContextChannel)myChannel).OperationTimeout = new Timespan(0, 5, 0);
Ваш адрес конечной точки в клиенте и на сервере указывает "localhost" в качестве имени машины. Если они находятся на разных машинах, клиент не сможет общаться с сервисом. Попробуйте изменить его на фактическое имя компьютера, на котором расположен сервер.
Обновление: вот пример WSDualHttpBinding, работающий с односторонними операциями как по контракту, так и по контракту обратного вызова. WSDualHttpBinding не требует, чтобы операции с контрактом обратного вызова были односторонними. PollingDuplexHttpBinding (для Silverlight) делает, но это другая история.
using System;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.Threading;
public class Stackru_6216605_751090
{
[ServiceContract(CallbackContract = typeof(ITestCallback))]
public interface ITest
{
[OperationContract]
int Add(int x, int y);
[OperationContract]
void CallMe(int numberOfTimes);
}
[ServiceContract]
public interface ITestCallback
{
[OperationContract]
string Hello(string name);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : ITest
{
public int Add(int x, int y)
{
Console.WriteLine("In a Request/Reply operation on server: {0} + {1}", x, y);
return x + y;
}
public void CallMe(int numberOfTimes)
{
Console.WriteLine("In another request/reply operation on server, which will call the client.");
ITestCallback callback = OperationContext.Current.GetCallbackChannel<ITestCallback>();
ThreadPool.QueueUserWorkItem(delegate
{
for (int i = 0; i < numberOfTimes; i++)
{
Console.WriteLine("Received from client: {0}", callback.Hello("Server"));
}
});
}
}
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ClientCallback : ITestCallback
{
static int count = 0;
public string Hello(string name)
{
Console.WriteLine("In a client operation, name = {0}", name);
return string.Format("[{0}] Hello, {1}", ++count, name);
}
}
static void PrintUsage()
{
string programName = Path.GetFileName(Assembly.GetEntryAssembly().CodeBase);
Console.WriteLine("Usage: {0} <options>", programName);
Console.WriteLine("Examples:");
Console.WriteLine(" Starting the server: {0} -server", programName);
Console.WriteLine(" Starting the client: {0} -client <serverMachineName>", programName);
}
public static void Main(string[] args)
{
if (args.Length < 1)
{
PrintUsage();
return;
}
if (args[0].Equals("-server", StringComparison.OrdinalIgnoreCase))
{
string serviceAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(serviceAddress));
host.AddServiceEndpoint(typeof(ITest), new WSDualHttpBinding(WSDualHttpSecurityMode.None), "");
host.Open();
Console.WriteLine("Host opened, press ENTER to close");
Console.ReadLine();
host.Close();
}
else if (args.Length > 1 && args[0].Equals("-client", StringComparison.OrdinalIgnoreCase))
{
string serviceAddress = "http://" + args[1] + ":8000/Service";
ClientCallback clientCallback = new ClientCallback();
DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
clientCallback,
new WSDualHttpBinding(WSDualHttpSecurityMode.None),
new EndpointAddress(serviceAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine("Simple Request/Reply: {0}", proxy.Add(3, 4));
Console.WriteLine("Now calling an operation on the server which will cause callbacks");
proxy.CallMe(10);
Console.WriteLine("Press ENTER to close");
Console.ReadLine();
}
else
{
PrintUsage();
}
}
}
Проверьте, пометили ли вы свой операционный контракт как один из способов. Обычно в двойном http-связывании получается тайм-аут, когда люди не могут пометить контракт как один из способов.
[OperationContract(IsOneWay = true)]
РЕДАКТИРОВАТЬ
Пожалуйста, поместите следующую строку в поведение контракта на обслуживание.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
Для справки рассмотрите возможность размещения вашей структуры контракта на обслуживание и выполнения контракта на эксплуатацию.