:
답변 (때문에 낮은 등급 회원에 유래의 이상한 정책 나중에 응답으로 추가됩니다).
우선, 사용자 지정 호출 처리기를 사용하여 로그에 필요한 모든 추가 데이터를 포함해야합니다. entlib 소스 코드를 참조하고 LogCallHandler를 찾을 수 있습니다. GetLogEntry 개인 방법에 추가 데이터를 추가
private TraceLogEntry GetLogEntry(IMethodInvocation input)
{
var logEntry = new CustomLogEntry();
var formatter = new CategoryFormatter(input.MethodBase);
foreach (string category in categories)
{
logEntry.Categories.Add(formatter.FormatCategory(category));
}
//slot = Thread.GetNamedDataSlot("PatientId");
//logEntry.PatientId = Thread.GetData(slot).ToString();
//logEntry.PatientId = CallContext.GetData("__PatientId").ToString();
logEntry.AppName = ApplicationContext.Current["AppName"].ToString();
logEntry.ClientIp = ApplicationContext.Current["ClientIp"].ToString();
logEntry.UserId = ApplicationContext.Current["UserId"].ToString();
logEntry.PatientId = ApplicationContext.Current["PatientId"].ToString();
logEntry.EventId = eventId;
logEntry.Priority = priority;
logEntry.Severity = severity;
logEntry.Title = LogCallHandlerDefaults.Title;
if (includeParameters)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
for (int i = 0; i < input.Arguments.Count; ++i)
{
parameters[input.Arguments.GetParameterInfo(i).Name] = input.Arguments[i];
}
logEntry.ExtendedProperties = parameters;
}
if (includeCallStack)
{
logEntry.CallStack = Environment.StackTrace;
}
logEntry.TypeName = input.Target.GetType().FullName;
logEntry.MethodName = input.MethodBase.Name;
return logEntry;
}
thatn 후에는 클라이언트에서 서버에 컨텍스트 데이터를 전파 할 infrastruture를 creat에해야합니다.
서비스 클라이언트에서
[Serializable]
public class ApplicationContext : Dictionary<string, object>
{
private const string CALL_CONTEXT_KEY = "__Context";
public const string ContextHeaderLocalName = "__Context";
public const string ContextHeaderNamespace = "urn:tempuri.org";
private static void EnsureSerializable(object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (!value.GetType().IsSerializable)
{
throw new ArgumentException(string.Format("The argument of the type \"{0}\" is not serializable!", value.GetType().FullName));
}
}
public new object this[string key]
{
get { return base[key]; }
set
{ EnsureSerializable(value); base[key] = value; }
}
public int Counter
{
get { return (int)this["__Count"]; }
set { this["__Count"] = value; }
}
public static ApplicationContext Current
{
get
{
if (CallContext.GetData(CALL_CONTEXT_KEY) == null)
{
CallContext.SetData(CALL_CONTEXT_KEY, new ApplicationContext());
}
return CallContext.GetData(CALL_CONTEXT_KEY) as ApplicationContext;
}
set
{
CallContext.SetData(CALL_CONTEXT_KEY, value);
}
}
}
,이 문맥 IClientMessageInspector 구현을 통해 요청 메시지 헤더에 추가됩니다 CallContext 컨텍스트 데이터에 대한 사전 객체를 저장하는 나는 래퍼 클래스가 있습니다.
public class AuditInfoCallContextInitializer : ICallContextInitializer
{
#region Implementation of ICallContextInitializer
/// <summary>
/// Extract context data from message header through local name and namespace,
/// set the data to ApplicationContext.Current.
/// </summary>
/// <param name="instanceContext"></param>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
var context = message.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);
if (context == null) { return null; }
ApplicationContext.Current = context;
return ApplicationContext.Current;
}
/// <summary>
/// Retrieve context from correlationState and store it back to reply message header for client.
/// </summary>
/// <param name="correlationState"></param>
public void AfterInvoke(object correlationState)
{
var context = correlationState as ApplicationContext;
if (context == null)
{
return;
}
var contextHeader = new MessageHeader<ApplicationContext>(context);
OperationContext.Current.OutgoingMessageHeaders.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));
ApplicationContext.Current = null;
}
#endregion
}
이 본질적으로 왕복입니다 : 서비스 측면에서
public class ClientAuditInfoInspector : IClientMessageInspector
{
#region Implementation of IClientMessageInspector
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var contextHeader = new MessageHeader<ApplicationContext>(ApplicationContext.Current);
request.Headers.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (reply.Headers.FindHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace) < 0) { return; }
var context = reply.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);
if (context == null) { return; }
ApplicationContext.Current = context;
}
#endregion
}
, 나는 수신 메시지에서 메시지 헤더를 검색하고 보내는 메시지로 다시 설정 ICallContextInitializer의 사용자 지정 구현을 메시지 헤더 페이로드가 이동하기 때문입니다. AfterInvoke 메서드에서 메시지 헤더를 다시 보내기 전에 수정할 수 있습니다. 마지막으로 MessageInspector 및 CallContextInitializer를 적용하기위한 끝점 동작을 만들었습니다.
public class AuditInfoContextPropagationEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
#region Overrides of BehaviorExtensionElement
protected override object CreateBehavior()
{
return new AuditInfoContextPropagationEndpointBehavior();
}
public override Type BehaviorType
{
get { return typeof(AuditInfoContextPropagationEndpointBehavior); }
}
#endregion
#region Implementation of IEndpointBehavior
public void Validate(ServiceEndpoint endpoint)
{
return;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)
{
operation.CallContextInitializers.Add(new AuditInfoCallContextInitializer());
}
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new ClientAuditInfoInspector());
}
#endregion
}
서비스/계약을 행동 특성으로 꾸미면 동일한 계약 행위를 작성할 수도 있습니다. 서비스 클라이언트에서 지금
, 당신은 다음과 같은 모든 상황에 맞는 데이터를 설정할 수 있습니다
using (var channelFactory = new ChannelFactory<ICustomerService>("WSHttpBinding_ICustomerService"))
{
var client = channelFactory.CreateChannel();
ApplicationContext.Current["AppName"] = "Test application";
ApplicationContext.Current["ClientIp"] = @"1.1.0.1";
ApplicationContext.Current["UserId"] = "foo";
ApplicationContext.Current["PatientId"] = "bar123";
Console.WriteLine("Retreiving Customer 1");
Customer cust = client.GetCustomer("1");
Console.WriteLine("Retreived Customer, Name: [" + cust.Name + "]");
}
이도에 entlib.codeplex의 토론 게시판에 게시가 : http://entlib.codeplex.com/discussions/266963
스택 오버플로 질문입니다 및 응답 사이트. 답변을 질문으로 게시 한 것 같습니다. 질문에서 대답을 제거하고 답변으로 게시해야합니다. –
예, 저는 그것을 깨달았습니다. 나는 매우 희미한 회색 색상의 편집 링크를 보지 못했습니다. 나는 이제 질문을 업데이트하고 5 시간 후에 대답을 추가 할 것이다. 그것을 지적 주셔서 감사합니다. – binjiezhao