#c# #.net #wcf
#c# #.net #wcf
Вопрос:
Я запускаю службу, которая выглядит как пример MS Calculator. Это интерфейс контракта ServiceContract.
[ServiceContract(Namespace = "http://localhost:8000/Calculator")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
Я настроил службу следующим образом:
public partial class Service1: ServiceBase
{
private static readonly string sNameOfService = "CalculatorService";
public static string NameOfService
{
get { return sNameOfService; }
}
public ServiceHost serviceHost = null;
public Service1()
{
InitializeComponent();
this.ServiceName = sNameOfService;
this.CanStop = true;
this.CanPauseAndContinue = false;
this.AutoLog = true;
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
serviceHost.Close();
Uri[] baseAddress = new Uri[]{
new Uri("net.pipe://localhost")};
string PipeName = "Calculator";
serviceHost = new ServiceHost(typeof(CalculatorImplementation),
serviceHost.AddServiceEndpoint(typeof(ICalculator), new NetNamedPipeBinding(), PipeName);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null amp;amp; serviceHost.State != CommunicationState.Closed)
{
serviceHost.Close();
serviceHost = null;
}
}
}
Я успешно установил службу, и она запущена на моем локальном компьютере.
Следующим шагом было настроить клиента для доступа к службе, что я и сделал следующим образом.
public interface ICalculator
{
// die einzelnen Teile können auch als Vorgänge bzw. Kanäle verstanden werden
// öffentliche Teile des Interfaces definieren
// diese werden durch das OperationContract Attribut identifiziert
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
class Program
{
static void Main(string[] args)
{
ChannelFactory<ICalculator> pipeFactory = new ChannelFactory<ICalculator>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/Calculator"));
ICalculator pipeProxy = pipeFactory.CreateChannel();
double erg = pipeProxy.Add(5, 6);
Console.WriteLine("Ergebnis: {0}", erg.ToString());
Console.ReadLine();
}
}
Но я получаю ActionNotSupportedException при попытке вызвать «pipeProxy.Add()», и я понятия не имею, почему это происходит.
Мой сервер настроен неправильно, или я что-то не так в клиенте, или я пропустил установку некоторых необходимых атрибутов? Я просмотрел несколько примеров с использованием именованных каналов, но не нашел ничего, что помогло бы мне решить мою проблему.
Кроме того, я спрашивал себя, в чем разница и где я должен использовать реализацию ServiceHost и реализацию NamedPipeClientStream / NamedPipeServerStream?
Ответ №1:
ActionNotSupportedException
выдается, когда ваш клиент использует действие SOAP, которое неизвестно серверу. По умолчанию имена действий SOAP выводятся из типов сервисных контрактов и операционных контрактов.
В вашем примере я вижу, что контракт определен дважды. Означает ли это, что и служба, и клиент имеют свое собственное определение ICalculator
? В таком случае без дальнейших усилий эти два контракта не совпадают, потому что они, скорее всего, находятся в разных пространствах имен, и ваш первый контракт определяет свое собственное пространство имен, тогда как второй — нет. Если вы хотите использовать один и тот же интерфейс, поместите его в отдельную сборку и ссылайтесь на сборку как из службы, так и из клиента. В противном случае вам придется просмотреть ServiceContract
OperationContract
атрибуты и и убедиться, что значения для Namespace
, Action
и ReplyAction
одинаковы в обоих интерфейсах.
Комментарии:
1. Спасибо! Это решение моей проблемы! Но мне интересно, есть ли другой способ подключения к конечной точке, фактически не зная, что это EndpointAddress, здесь: net.pipe://localhost/Calculator . Имеет ли это какое-то отношение к ServiceMetadataBehavior, который заполняет конечную точку внешним миром?