【问题标题】:Shared information between a MessageInspector and a web-serviceMessageInspector 和 Web 服务之间的共享信息
【发布时间】:2013-03-13 23:19:24
【问题描述】:

我有一个关于在 MessageInspector 和 Web 服务之间共享信息的问题。

我有一个标识符 (Guid),用于“绑定”AfterReceiveRequest 和 BeforeSendReply。它工作正常。但我希望这个标识符也可以在 Web 服务中使用的方法中使用。这非常有用,例如用于跟踪日志中的问题。

下面是一个小的演示示例来说明这个想法。我的问题是找到一个解决方案,可以从 AfterReceiveRequest 方法访问返回对象。与“MagicStuff”一致。

namespace Demo.MessageInspector
{
    public class DemoMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            Guid activityId = Guid.NewGuid();
            MyLog.Message("AfterReceiveRequest", activityId);
            return activityId;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            Guid activityId = (Guid)correlationState;
            MyLog.Message("BeforeSendReply", activityId);
        }
    }
}

namespace Demo.WebServices
{
    [ServiceBehavior]
    [MessageInterceptionServiceBehaviour]
    public class MyWebService : IMyWebService
    {
        public void MyWebServiceMethod()
        {
            Guid activityId = (Guid)MagicStuff; // <-- correlationState from AfterReceiveRequest

            bool success = DoSomthing();

            if (!success)
                MyLog.Message("Error happened in MyWebServiceMethod", activityId);
        }
    }
}

如果能提供任何帮助或提示,我将不胜感激。

【问题讨论】:

  • 你读过IDispatchMessageInspector Interface这个话题了吗?
  • 是的,我已经阅读了您所指的描述 - 不幸的是,没有找到解决我问题的方法。但这对我来说是一个新领域,我不太可能误解了此功能的某些部分。

标签: c# web-services variables idispatchmessageinspector


【解决方案1】:

您可以使用OperationContext.IncomingMessageProperties Property。这是您的场景中的用法:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Demo.MessageInspector;
using Demo.Utilities;

namespace Demo.WebServices
{
    public class MyWebService : IMyWebService, IServiceBehavior
    {
        public void MyWebServiceMethod()
        {
            // get the activityId from the incoming message properties
            var activityIdProperty = OperationContext.Current.IncomingMessageProperties
                .FirstOrDefault(property => property.Key == Properties.ActivityId.ToString());

            // create an empty Guid
            Guid activityId = new Guid();
            if (activityIdProperty.Value != null)
            {
                // replace the empty Guid with the activityId
                activityId = (Guid)activityIdProperty.Value;
            }
            bool success = DoSomething();
            if (!success)
                MyLog.Message("Error happened in MyWebServiceMethod", activityId);
        }

        private bool DoSomething()
        {
            // TODO: implement
            return false;
        }

        public void AddBindingParameters(
          ServiceDescription serviceDescription,
          ServiceHostBase serviceHostBase,
          System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
          BindingParameterCollection bindingParameters
        )
        {
            return;
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
            ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher chDisp in serviceHostBase.ChannelDispatchers)
            {
                foreach (EndpointDispatcher epDisp in chDisp.Endpoints)
                {
                    var messageInspector = new DemoMessageInspector();
                    epDisp.DispatchRuntime.MessageInspectors.Add(messageInspector);
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase)
        {
            // TODO: implement validation
            //throw new NotImplementedException();
        }
    }
}

namespace Demo.MessageInspector
{
    public class DemoMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, 
            IClientChannel channel, InstanceContext instanceContext)
        {
            Guid activityId = Guid.NewGuid();

            // add the activityId to the incoming message properties
            OperationContext.Current.IncomingMessageProperties
                .Add(Properties.ActivityId.ToString(), activityId);

            MyLog.Message("AfterReceiveRequest", activityId);
            return activityId;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            Guid activityId = (Guid)correlationState;
            MyLog.Message("BeforeSendReply", activityId);
        }
    }
}

namespace Demo.Utilities
{
    public enum Properties
    {
        ActivityId
    }

    public class MyLog
    {
        internal static void Message(string p, Guid guid)
        {
            File.AppendAllText(@"C:\Temp\log.txt", 
                String.Format("{0} {1} {2}\r\n", DateTime.Now, p, guid));
        }
    }
}

[更新]

或者,您可以使用CorrelationManager.ActivityId Property。为此,首先将以下内容添加到您的配置文件( 客户端和服务器):

<system.diagnostics>
  <sources>
    <source name="System.ServiceModel" propagateActivity="true">
      <listeners>
        <add name="ignored" type="System.Diagnostics.DefaultTraceListener" />
      </listeners>
    </source>
  </sources>
</system.diagnostics>

然后,在Demo.Utilities.Helper 类中添加以下方法:

namespace Demo.Utilities
{
    internal class Helper
    {
        internal static Guid GetCorrelationId()
        {
            var headerPosition = OperationContext.Current.IncomingMessageHeaders.FindHeader("ActivityId",
                "http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics");
            if (headerPosition > -1)
            {
                var activityIdHeader = OperationContext.Current.IncomingMessageHeaders
                    .GetReaderAtHeader(headerPosition);
                var activityIdAttribute = activityIdHeader.GetAttribute("CorrelationId");
                return Guid.Parse(activityIdAttribute);
            }
            else
            {
                return Guid.Empty;
            }
        }
    }
}

现在你可以在DemoMessageInspector中使用这样的方法:

public object AfterReceiveRequest(ref Message request,
    IClientChannel channel, InstanceContext instanceContext)
{
    var correlationId = Helper.GetCorrelationId();
    MyLog.Message("AfterReceiveRequest\tCorrelationId", correlationId);
    // ...
}

在你的服务方法中像这样:

public void MyWebServiceMethod()
{
    var correlationId = Helper.GetCorrelationId();
    MyLog.Message("MyWebServiceMethod\tCorrelationId", correlationId);

    // ...
}

【讨论】:

  • 谢谢亚历克斯。你的建议看起来很有趣。我会尝试并尽快得到结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2016-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多