如何在控制台服务主机中包含WCF自定义头



在我的WCF服务中,我得到405 method not allowed错误,然后遇到一个帖子,建议在我的WCF主机的Application_BeginRequest中有以下内容:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
                    "Accept, Content-Type,customHeader");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods",
                    "POST,GET,OPTIONS");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
                    "172800");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials",
                    "true");
        HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers",
                    "customHeader");
        HttpContext.Current.Response.AddHeader("Content-type",
                    "application/json");
        HttpContext.Current.Response.End();
    }
    else
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
                    "Accept, Content-Type,customHeader");
        HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers",
                    "customHeader");
        HttpContext.Current.Response.AddHeader("Content-type",
                    "application/json");
    }
} 

但是我使用控制台应用程序托管我的服务。

using (ServiceHost sc = new ServiceHost(typeof(DataRetriever)))
{
    sc.Open();
    foreach (var endPoints in sc.Description.Endpoints)
    {
        Console.WriteLine(endPoints.Address);
    }
    Console.ReadKey();
    sc.Close();
}

那么我如何在控制台应用程序中包含标头呢?

在WCF中,头文件可以通过类OperationContext的实例访问,而类OperationContext可以通过OperationContext访问。当前(可用时)。

解决这个问题最简单的方法就是在你的服务的方法中使用这个属性:
[ServiceContract]
public interface IMyService
{
    [OperationContract]
    void MyMethod();
}
internal class MyService: IMyService
{
    public void MyMethod()
    {
        Console.WriteLine("My Method");
        OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("headerFromMethod", "namespace", "headerFromMethodValue"));
    }
}
为了完整起见,用于在控制台应用程序中托管此服务的代码(不需要配置)是:
using (var serviceHost = new ServiceHost(typeof(MyService)))
{
    var endpoint = serviceHost.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "http://localhost:9000");
    serviceHost.Open();
    Console.WriteLine("Open for business");
    Console.ReadLine();
    serviceHost.Close();
}

.NET客户端会像这样访问报头:

var channel = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:9000"));
var contextChannel = channel as IContextChannel;
using (new OperationContextScope(contextChannel))
{
    channel.MyMethod();
    var incommingHeaders = OperationContext.Current.IncomingMessageHeaders;
    var header = incommingHeaders.GetHeader<string>("headerFromMethod", "namespace");
    Console.WriteLine("Header from server: " + header);
}

如果你有Fiddler,你也可以使用这个工具看到标题

虽然这个方法可以做你想做的,但你是否想要混合你的业务逻辑(包含在IMyService的实现中),以及控制附加到消息的"带外"信息的逻辑是值得怀疑的。

通过实现IDispatchMessageInspector可以获得更清晰的分离,它允许您拦截服务器上的调用,并在消息进出时修改消息:

public class ServerInterceptor: IDispatchMessageInspector, IEndpointBehavior
{
    object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        return null;
    }
    void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
    {
        reply.Headers.Add(MessageHeader.CreateHeader("header", "namespace", "headervalue"));
    }
    void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
    }
    void IEndpointBehavior.Validate(ServiceEndpoint endpoint){}
    void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){}
    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime){}
}

从. net客户端以与以前相同的方式访问头。值得注意的是,您可以将信息从AfterReceiveRequest方法传递给BeforeSendReply,因为前一个方法中返回的对象是作为correlationState参数传递给后一个方法的。如果您返回的报头依赖于传入消息的报头,这将是有用的-正如您的示例所示。

最后,要在服务上安装此功能,您需要修改托管代码,如下所示:

...
var endpoint = serviceHost.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "http://localhost:9000");
endpoint.Behaviors.Add(new ServerInterceptor());
serviceHost.Open();
...
我们可以这样做,因为ServerInterceptor实现了IEndpointBehavior

这可以做到。您需要一个在主机(控制台)exe和web服务类之间运行的共享变量。在调用WebService.Open()之后,必须运行一个连续的循环,检查这个共享变量是否有输入。代码看起来像这样:

//this would be your console host class
public class HostInterface
{
    string sHeaderString;
    public static string HeaderString {
        get { return sHeaderString; }
        set { sHeaderString += value; }

   public void main()
   {
      //code to start the web service
      System.ServiceModel.ServiceHost myWebService = default(System.ServiceModel.ServiceHost);
      //configure myWebService stuff
      myWebService.open();
      // here loop every second until the communication is stopped
      //check for new text in the shared sHeaderString 
      //written to by your web service class
      while (true) {
        if (myWebService.state != Communicationsstate.Opened){
            break; 
        }
        //write message out through console
        console.writeline("Headers:" + sHeaderString);
        Threading.Thread.Sleep(1000);
        //sleep 1 second before going trying next
      }
    }
  }
}

这将在你的web服务的主类中,从你的控制台引用和更新"HeaderString"共享变量。

public void WriteHeadersToSharedVariable()
{
        //here, setting the headers into the shared variable instanced back on the console program
        HostInterface.Headerstring = GetHeadersFromRequest();
}
public string GetHeadersFromRequest()
{
    //some code to get the headers from inbound request
    return "blah blah blah";
}

希望这对你有用。祝你好运。

相关内容

  • 没有找到相关文章

最新更新