2012-12-19 33 views
9

Tôi đang làm việc trên một dự án ASP.NET Web API trong C# cho một giao diện JSON cho một ứng dụng di động. Ý tưởng của tôi là tạo giao diện cho tất cả các yêu cầu và sau đó chỉ sử dụng các giao diện này trong mã API Web.Sự tiêm phụ thuộc vào các tham số phương thức hành động ASP.NET Web API

tôi đã kết thúc với một cái gì đó như thế này:

public interface IApiObject {} 
public interface IApiResponse<T> : IApiObject where T : IApiObject {} 
public interface IApiRegistrationRequest : IApiObject {} 

điều khiển của tôi trông như thế này:

public class MyApiController : ApiController 
{ 

    public IApiResponse<IApiObject> Register(IApiRegistrationRequest request) { 
     // do some stuff 
    } 
} 

dự án Web API của tôi cũng chứa hiện thực của các giao diện.

Tôi cho rằng các dự án API Web sử dụng mô hình ràng buộc như dự án MVC, vì vậy tôi đã tạo một inheritance aware ModelBinderProvider để cung cấp một chất kết dính cho tất cả các IApiObject và một bộ mô hình tùy chỉnh sử dụng một thùng chứa Unity để giải quyết các giao diện.

Tuy nhiên, sau khi điều tra thêm, tôi đã xem qua How Web API does parameter binding và phát hiện ra rằng Web API sử dụng các trình định dạng thay vì các mô hình kết dính cho các loại phức tạp. Bài đăng trên blog được liên kết đề xuất sử dụng một ModelBinderAttribute trên các tham số hành động của tôi, nhưng thuộc tính đó chỉ chấp nhận một kiểu làm tham số. Tuy nhiên, trình mô hình tùy chỉnh của tôi không chứa một hàm tạo rỗng (nó cần một thùng chứa thống nhất), vì vậy tôi sẽ cần phải chuyển một thể hiện của nó.

Cách khác tôi có thể nghĩ là sử dụng tính năng tiêm phụ thuộc cho các trình định dạng. Thật không may, tôi không quen với họ như tôi chưa bao giờ sử dụng chúng trước đây.

Cách nào phù hợp để đi? Và làm thế nào để tôi làm điều đó?

Trả lời

5

Đây là những gì tôi đã đưa ra bây giờ và nó hoạt động.

Tôi đã quyết định tạo trình định dạng tùy chỉnh, tính hợp nhất sẽ gọi và chuyển tiếp tất cả các thao tác khác sang trình định dạng khác bằng cách sử dụng loại được giải quyết. Nó trông giống như rất nhiều mã, nhưng đó là chỉ vì tất cả các phương pháp cần phải được ghi đè để loại luôn luôn có thể được giải quyết.

public class UnityFormatter : MediaTypeFormatter 
{ 
    private MediaTypeFormatter formatter; 

    private IUnityContainer container; 

    public UnityFormatter(MediaTypeFormatter formatter, IUnityContainer container) 
    { 
     this.formatter = formatter; 
     this.container = container; 

     foreach (var supportedMediaType in this.formatter.SupportedMediaTypes) 
     { 
      this.SupportedMediaTypes.Add(supportedMediaType); 
     } 

     foreach (var supportedEncoding in this.formatter.SupportedEncodings) 
     { 
      this.SupportedEncodings.Add(supportedEncoding); 
     } 

     foreach (var mediaTypeMapping in this.MediaTypeMappings) 
     { 
      this.MediaTypeMappings.Add(mediaTypeMapping); 
     } 

     this.RequiredMemberSelector = this.formatter.RequiredMemberSelector; 
    } 

    private Type ResolveType(Type type) 
    { 
     return this.container.Registrations.Where(n => n.RegisteredType == type).Select(n => n.MappedToType).FirstOrDefault() ?? type; 
    } 

    public override bool CanReadType(Type type) 
    { 
     return this.formatter.CanReadType(this.ResolveType(type)); 
    } 

    public override bool CanWriteType(Type type) 
    { 
     return this.formatter.CanWriteType(this.ResolveType(type)); 
    } 

    public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType) 
    { 
     return this.formatter.GetPerRequestFormatterInstance(this.ResolveType(type), request, mediaType); 
    } 

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) 
    { 
     return this.formatter.ReadFromStreamAsync(this.ResolveType(type), readStream, content, formatterLogger); 
    } 

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) 
    { 
     this.formatter.SetDefaultContentHeaders(this.ResolveType(type), headers, mediaType); 
    } 

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) 
    { 
     return this.formatter.WriteToStreamAsync(this.ResolveType(type), value, writeStream, content, transportContext); 
    } 
} 

Cuối cùng, đăng ký trình định dạng tùy chỉnh của chúng tôi trong cấu hình ứng dụng (Global.asax Application_Start). Tôi đã chọn để thay thế tất cả các trình định dạng hiện tại bằng một phiên bản tùy chỉnh của tôi, vì vậy tôi nhận được sự phản ánh cho tất cả các kiểu dữ liệu.

// set up unity container, register all types 
UnityContainer container = new UnityContainer(); 
container.RegisterType<IApiRegistrationRequest, ApiRegistrationRequest>(); 

// save existing formatters and remove them from the config 
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>(GlobalConfiguration.Configuration.Formatters); 
GlobalConfiguration.Configuration.Formatters.Clear(); 

// create an instance of our custom formatter for each existing formatter 
foreach (MediaTypeFormatter formatter in formatters) 
{ 
    GlobalConfiguration.Configuration.Formatters.Add(new UnityFormatter(formatter, container)); 
} 
2

tôi đề nghị bạn có một cái nhìn tại Dịch vụ stack http://www.servicestack.net/

của nó có giống nhau tất cả xung quanh thiết kế như asp.net-WebAPI nhưng nó có goodies như IOC nướng vào nó.

Có một loạt tuyệt vời về dịch vụ ngăn xếp ở http://pluralsight.com/training/Courses/TableOfContents/service-stack

+0

Cảm ơn, điều này có vẻ thú vị, nhưng tôi không thể dễ dàng thay đổi công nghệ ngay bây giờ. – Chris

Các vấn đề liên quan