2012-04-14 40 views
3

我已经写了叫RequestWrapper此类一个简单的对象,它包含类型的一个方法:实施RequestWrapper此类REST风格的WCF服务

TResult WrapRequest<TResult>(Func<TResult> action) 

它封装了try..catch任何行动,错误处理,日志记录,数据库连接,事务(提交&回滚)等

目前我使用这样的:(例如,不生产代码)

return RequestWrapper.WrapRequest(() => 
{ 
    Topic entity = GetRepository<Topic>().Find(uid); 

    if (entity == null) 
     throw new EntityNotFoundException("Topic not found."); 

    return new Topic 
    { 
     Name = entity.Name, 
     Posts = entity.Posts.Select(x => new Post 
     { 
      Body = x.Body, 
     }).ToList() 
    }; 
}); 

我只是环绕我的REST风格的Web服务的每个方法(使用WCF和WebHttpBinding)。

我的问题是:我应该如何实现自动执行包装的行为?这可能吗?

回答

4

您可以使用自定义IOperationInvoker,它包装原来的一个做你所需要的。下面的代码显示了一个示例实现,您可以在http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/17/wcf-extensibility-ioperationinvoker.aspx找到更多关于invokers的信息。

public class StackOverflow_10156890 
{ 
    [ServiceContract] 
    public interface ITest 
    { 
     [WebGet] 
     [WrappedOperationBehavior] 
     string Echo(string text); 
     [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)] 
     [WrappedOperationBehavior] 
     int Divide(int x, int y); 
    } 
    public class Service : ITest 
    { 
     public string Echo(string text) 
     { 
      return text; 
     } 
     public int Divide(int x, int y) 
     { 
      return x/y; 
     } 
    } 
    class RequestWrapperOperationInvoker : IOperationInvoker 
    { 
     IOperationInvoker originalInvoker; 

     public RequestWrapperOperationInvoker(IOperationInvoker originalInvoker) 
     { 
      this.originalInvoker = originalInvoker; 
     } 

     public object[] AllocateInputs() 
     { 
      return this.originalInvoker.AllocateInputs(); 
     } 

     public object Invoke(object instance, object[] inputs, out object[] outputs) 
     { 
      Console.WriteLine("Do initialization, etc. here"); 
      object result = null; 
      try 
      { 
       result = this.originalInvoker.Invoke(instance, inputs, out outputs); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Log exception: {0}: {1}", e.GetType().FullName, e.Message); 
       result = null; 
       outputs = null; 
      } 
      finally 
      { 
       Console.WriteLine("Do finalization, etc. here"); 
      } 

      return result; 
     } 

     public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
     { 
      throw new NotSupportedException("Only synchronous operations supported"); 
     } 

     public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
     { 
      throw new NotSupportedException("Only synchronous operations supported"); 
     } 

     public bool IsSynchronous 
     { 
      get { return true; } 
     } 
    } 
    class WrappedOperationBehaviorAttribute : Attribute, IOperationBehavior 
    { 
     public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
     { 
     } 

     public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
     { 
      dispatchOperation.Invoker = new RequestWrapperOperationInvoker(dispatchOperation.Invoker); 
     } 

     public void Validate(OperationDescription operationDescription) 
     { 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     var endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), ""); 
     endpoint.Behaviors.Add(new WebHttpBehavior()); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     WebClient c = new WebClient(); 
     Console.WriteLine(c.DownloadString(baseAddress + "/Echo?text=Hello%20world")); 

     c = new WebClient(); 
     c.Headers[HttpRequestHeader.ContentType] = "application/json"; 
     Console.WriteLine(c.UploadString(baseAddress + "/Divide", "{\"x\":12,\"y\":0}")); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 
+0

好的和完整的解决方案,非常感谢。 :) – 2012-04-24 21:56:42