通常,您可以像这样从OperationContext
中get the service instance:
OperationContext.Current.InstanceContext.GetServiceInstance()
但是,当您使用
IAuthorizationPolicy
时,InstanceContext
为null。托管在IIS中时,还有另一种获取服务实例的方法吗? 最佳答案
在IAuthorizationPolicy.Evaluate()
中,OperationContext.Current.InstanceContext
并不总是为null。
以Carlos Figueira’s WCF Extensibility test program开头,每次调用WCF扩展名时,该命令都会在命令行中显示一条消息。我添加了一个自定义的IAuthorizationPolicy。输出和程序如下。
输出显示
创建服务实例后调用IAuthorizationPolicy.Evaluate()
OperationContext.Current.InstanceContext
在IAuthorizationPolicy.Evaluate()
中不为空
测试程序是使用BasicHttpBinding自托管的。在其他托管环境中,很有可能IAuthorizationPolicy.Evaluate()无法访问服务实例,但至少在理论上是可行的。
你为什么要这样做?
从体系结构的角度来看,IAuthorizationPolicy应该处理声明。该应用程序应该使用ClaimsPrinciple上的索赔。将IAuthorizationPolicy与特定服务紧密耦合会破坏Window Identity体系结构中非常有意的关注点分离。换句话说,我认为这是一个坏主意。
测试程序
这是一个Windows命令行程序,位于一个文件中。
using System;
using System.Globalization;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading;
using System.Collections.Generic;
namespace WcfRuntime
{
class MyDispatchMessageInspector : IDispatchMessageInspector
{
public MyDispatchMessageInspector()
{
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
}
class MyDispatchMessageFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter inner;
public MyDispatchMessageFormatter(IDispatchMessageFormatter inner)
{
this.inner = inner;
}
public void DeserializeRequest(Message message, object[] parameters)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
this.inner.DeserializeRequest(message, parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.SerializeReply(messageVersion, parameters, result);
}
}
class MyClientMessageInspector : IClientMessageInspector
{
public MyClientMessageInspector()
{
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return null;
}
}
class MyClientMessageFormatter : IClientMessageFormatter
{
IClientMessageFormatter inner;
public MyClientMessageFormatter(IClientMessageFormatter inner)
{
this.inner = inner;
}
public object DeserializeReply(Message message, object[] parameters)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.SerializeRequest(messageVersion, parameters);
}
}
class MyDispatchOperationSelector : IDispatchOperationSelector
{
public string SelectOperation(ref Message message)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
string action = message.Headers.Action;
string method = action.Substring(action.LastIndexOf('/') + 1);
return method;
}
}
class MyParameterInspector : IParameterInspector
{
ConsoleColor consoleColor;
bool isServer;
public MyParameterInspector(bool isServer)
{
this.isServer = isServer;
this.consoleColor = isServer ? ConsoleColor.Cyan : ConsoleColor.Yellow;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
public object BeforeCall(string operationName, object[] inputs)
{
ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return null;
}
}
class MyCallContextInitializer : ICallContextInitializer
{
public void AfterInvoke(object correlationState)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return null;
}
}
class MyOperationInvoker : IOperationInvoker
{
IOperationInvoker inner;
public MyOperationInvoker(IOperationInvoker inner)
{
this.inner = inner;
}
public object[] AllocateInputs()
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.Invoke(instance, inputs, out outputs);
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.InvokeEnd(instance, out outputs, result);
}
public bool IsSynchronous
{
get
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.IsSynchronous;
}
}
}
class MyInstanceProvider : IInstanceProvider
{
Type serviceType;
public MyInstanceProvider(Type serviceType)
{
this.serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return Activator.CreateInstance(this.serviceType);
}
public object GetInstance(InstanceContext instanceContext)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return Activator.CreateInstance(this.serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
}
class MyInstanceContextProvider : IInstanceContextProvider
{
IInstanceContextProvider inner;
public MyInstanceContextProvider(IInstanceContextProvider inner)
{
this.inner = inner;
}
public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.GetExistingInstanceContext(message, channel);
}
public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
this.inner.InitializeInstanceContext(instanceContext, message, channel);
}
public bool IsIdle(InstanceContext instanceContext)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return this.inner.IsIdle(instanceContext);
}
public void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
this.inner.NotifyIdle(callback, instanceContext);
}
}
class MyInstanceContextInitializer : IInstanceContextInitializer
{
public void Initialize(InstanceContext instanceContext, Message message)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
}
class MyChannelInitializer : IChannelInitializer
{
ConsoleColor consoleColor;
public MyChannelInitializer(bool isServer)
{
this.consoleColor = isServer ? ConsoleColor.Cyan : ConsoleColor.Yellow;
}
public void Initialize(IClientChannel channel)
{
ColorConsole.WriteLine(this.consoleColor, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
}
class MyClientOperationSelector : IClientOperationSelector
{
public bool AreParametersRequiredForSelection
{
get
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return false;
}
}
public string SelectOperation(MethodBase method, object[] parameters)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return method.Name;
}
}
class MyInteractiveChannelInitializer : IInteractiveChannelInitializer
{
public IAsyncResult BeginDisplayInitializationUI(IClientChannel channel, AsyncCallback callback, object state)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
Action act = new Action(this.DoNothing);
return act.BeginInvoke(callback, state);
}
public void EndDisplayInitializationUI(IAsyncResult result)
{
ColorConsole.WriteLine(ConsoleColor.Yellow, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
}
private void DoNothing() { }
}
class MyErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
return error is ArgumentException;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
ColorConsole.WriteLine(ConsoleColor.Cyan, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
MessageFault messageFault = MessageFault.CreateFault(new FaultCode("FaultCode"), new FaultReason(error.Message));
fault = Message.CreateMessage(version, messageFault, "FaultAction");
}
}
public class MyAuthorizationPolicy : IAuthorizationPolicy
{
string id;
public MyAuthorizationPolicy()
{
id = Guid.NewGuid().ToString();
}
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
ColorConsole.WriteLine(ConsoleColor.Green, "{0}.{1}", this.GetType().Name, ReflectionUtil.GetMethodSignature(MethodBase.GetCurrentMethod()));
if (OperationContext.Current.InstanceContext != null)
{
var instance = (Service)OperationContext.Current.InstanceContext.GetServiceInstance();
ColorConsole.WriteLine(ConsoleColor.Green, "Got the service instance. Name={0}", instance.Name);
}
else
{
ColorConsole.WriteLine(ConsoleColor.Green, "OperationContext.Current.InstanceContext is null");
}
// Return true, indicating that this method does not need to be called again.
return true;
}
public ClaimSet Issuer
{
get { return ClaimSet.System; }
}
public string Id
{
get { return id; }
}
}
[ServiceContract]
public interface ITest
{
[OperationContract]
int Add(int x, int y);
[OperationContract(IsOneWay = true)]
void Process(string text);
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Service : ITest
{
public Service() { ColorConsole.WriteLine(ConsoleColor.Green, "Created Service Instance"); }
public string Name { get { return "MyService instance 1234"; } }
public int Add(int x, int y)
{
ColorConsole.WriteLine(ConsoleColor.Green, "In service operation '{0}'", MethodBase.GetCurrentMethod().Name);
if (x == 0 && y == 0)
{
throw new ArgumentException("This will cause IErrorHandler to be called");
}
else
{
return x + y;
}
}
public void Process(string text)
{
ColorConsole.WriteLine(ConsoleColor.Green, "In service operation '{0}'", MethodBase.GetCurrentMethod().Name);
}
}
class MyBehavior : IOperationBehavior, IContractBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
clientOperation.Formatter = new MyClientMessageFormatter(clientOperation.Formatter);
clientOperation.ParameterInspectors.Add(new MyParameterInspector(false));
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.CallContextInitializers.Add(new MyCallContextInitializer());
dispatchOperation.Formatter = new MyDispatchMessageFormatter(dispatchOperation.Formatter);
dispatchOperation.Invoker = new MyOperationInvoker(dispatchOperation.Invoker);
dispatchOperation.ParameterInspectors.Add(new MyParameterInspector(true));
}
public void Validate(OperationDescription operationDescription)
{
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ChannelInitializers.Add(new MyChannelInitializer(false));
clientRuntime.InteractiveChannelInitializers.Add(new MyInteractiveChannelInitializer());
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector());
clientRuntime.OperationSelector = new MyClientOperationSelector();
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.ChannelDispatcher.ChannelInitializers.Add(new MyChannelInitializer(true));
dispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(new MyErrorHandler());
dispatchRuntime.InstanceContextInitializers.Add(new MyInstanceContextInitializer());
dispatchRuntime.InstanceContextProvider = new MyInstanceContextProvider(dispatchRuntime.InstanceContextProvider);
dispatchRuntime.InstanceProvider = new MyInstanceProvider(dispatchRuntime.ChannelDispatcher.Host.Description.ServiceType);
dispatchRuntime.MessageInspectors.Add(new MyDispatchMessageInspector());
dispatchRuntime.OperationSelector = new MyDispatchOperationSelector();
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
}
static class ColorConsole
{
static object syncRoot = new object();
public static void WriteLine(ConsoleColor color, string text, params object[] args)
{
if (args != null && args.Length > 0)
{
text = string.Format(CultureInfo.InvariantCulture, text, args);
}
lock (syncRoot)
{
Console.ForegroundColor = color;
Console.WriteLine("[{0}] {1}", DateTime.Now.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture), text);
Console.ResetColor();
}
Thread.Sleep(50);
}
public static void WriteLine(string text, params object[] args)
{
Console.WriteLine(text, args);
}
public static void WriteLine(object obj)
{
Console.WriteLine(obj);
}
}
static class ReflectionUtil
{
public static string GetMethodSignature(MethodBase method)
{
StringBuilder sb = new StringBuilder();
sb.Append(method.Name);
sb.Append("(");
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
if (i > 0) sb.Append(", ");
sb.Append(parameters[i].ParameterType.Name);
}
sb.Append(")");
return sb.ToString();
}
}
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
using (ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)))
{
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
endpoint.Contract.Behaviors.Add(new MyBehavior());
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
operation.Behaviors.Add(new MyBehavior());
}
var polices = new List<IAuthorizationPolicy>();
polices.Add(new MyAuthorizationPolicy());
host.Authorization.ExternalAuthorizationPolicies = polices.AsReadOnly();
host.Open();
ColorConsole.WriteLine("Host opened");
using (ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress)))
{
factory.Endpoint.Contract.Behaviors.Add(new MyBehavior());
foreach (OperationDescription operation in factory.Endpoint.Contract.Operations)
{
operation.Behaviors.Add(new MyBehavior());
}
ITest proxy = factory.CreateChannel();
ColorConsole.WriteLine("Calling operation");
ColorConsole.WriteLine(proxy.Add(3, 4));
//ColorConsole.WriteLine("Called operation, calling it again, this time it the service will throw");
//try
//{
// ColorConsole.WriteLine(proxy.Add(0, 0));
//}
//catch (Exception e)
//{
// ColorConsole.WriteLine(ConsoleColor.Red, "{0}: {1}", e.GetType().Name, e.Message);
//}
//ColorConsole.WriteLine("Now calling an OneWay operation");
//proxy.Process("hello");
((IClientChannel)proxy).Close();
}
}
ColorConsole.WriteLine("Done");
}
}
}
节目输出
寻找---->。
[12:33:04.218] MyOperationInvoker.get_IsSynchronous()
[12:33:04.269] MyOperationInvoker.get_IsSynchronous()
Host opened
[12:33:04.322] MyChannelInitializer.Initialize(IClientChannel)
Calling operation
[12:33:04.373] MyClientOperationSelector.get_AreParametersRequiredForSelection()
[12:33:04.424] MyClientOperationSelector.SelectOperation(MethodBase, Object[])
[12:33:04.474] MyParameterInspector.BeforeCall(String, Object[])
[12:33:04.524] MyClientMessageFormatter.SerializeRequest(MessageVersion, Object[])
[12:33:04.574] MyClientMessageInspector.BeforeSendRequest(Message&, IClientChannel)
[12:33:04.632] MyInteractiveChannelInitializer.BeginDisplayInitializationUI(IClientChannel, AsyncCallback, Object)
[12:33:04.684] MyInteractiveChannelInitializer.EndDisplayInitializationUI(IAsyncResult)
[12:33:04.788] MyChannelInitializer.Initialize(IClientChannel)
[12:33:04.838] MyInstanceContextProvider.GetExistingInstanceContext(Message, IContextChannel)
[12:33:04.888] MyDispatchOperationSelector.SelectOperation(Message&)
[12:33:04.939] MyInstanceContextProvider.InitializeInstanceContext(InstanceContext, Message, IContextChannel)
[12:33:04.990] MyInstanceContextInitializer.Initialize(InstanceContext, Message)
[12:33:05.040] MyDispatchMessageInspector.AfterReceiveRequest(Message&, IClientChannel, InstanceContext)
[12:33:05.091] MyInstanceProvider.GetInstance(InstanceContext, Message)
[12:33:05.142] Created Service Instance
[12:33:05.192] MyCallContextInitializer.BeforeInvoke(InstanceContext, IClientChannel, Message)
[12:33:05.242] MyOperationInvoker.AllocateInputs()
[12:33:05.293] MyDispatchMessageFormatter.DeserializeRequest(Message, Object[])
[12:33:05.344] MyParameterInspector.BeforeCall(String, Object[])
[12:33:05.394] MyAuthorizationPolicy.Evaluate(EvaluationContext, Object&)
---->[12:33:05.445] Got the service instance. Name=MyService instance 1234
[12:33:05.495] MyOperationInvoker.Invoke(Object, Object[], Object[]&)
[12:33:05.547] In service operation 'Add'
[12:33:05.597] MyParameterInspector.AfterCall(String, Object[], Object, Object)
[12:33:05.648] MyDispatchMessageFormatter.SerializeReply(MessageVersion, Object[], Object)
[12:33:05.698] MyCallContextInitializer.AfterInvoke(Object)
[12:33:05.748] MyDispatchMessageInspector.BeforeSendReply(Message&, Object)
[12:33:05.803] MyInstanceContextProvider.IsIdle(InstanceContext)
[12:33:05.804] MyClientMessageInspector.AfterReceiveReply(Message&, Object)
[12:33:05.854] MyInstanceProvider.ReleaseInstance(InstanceContext, Object)
[12:33:05.855] MyClientMessageFormatter.DeserializeReply(Message, Object[])
[12:33:05.905] MyParameterInspector.AfterCall(String, Object[], Object, Object)