Элементы веб-API WCF, найденные в нескольких методах - PullRequest
6 голосов
/ 20 мая 2011

Допустим, я использую новый веб-API WCF для создания службы RESTful, и в моем сервисе есть раздел URI, который будет описывать целевой ресурс, но используется (почти) во всех методах контракта.,Например, если у меня есть служба пользователя, которая имеет дело с электронной коммерцией и может выглядеть следующим образом:

[ServiceContract]
public class MyUserService
{
    private MyUserRepository _UserRepo;
    private MyOrganizationRepository _OrgRepo;

    [WebGet (UriTemplate = "{OrganizationName}/Users")]
    public IEnumerable<User> GetUsers (string OrganizationName)
    {
        IEnumerable<User> Users = null;
        var Organization = _OrgRepo.GetOrgByName (OrganizationName);

        if (Organization != null)
        {
            Users = Organization.GetUsers ();
        }
        else
        {
            throw new WebFaultException<string> ("Organization not found.", HttpStatusCode.NotFound);
        }

        return Users;
    }

    [WebInvoke (UriTemplate = "{OrganizationName}/Users", /*yada...yada...yada*/)]
    public User AddNewUser (string OrganizationName, User User)
    {
        // Find the organization, like above, and throw if null.
    }
}

Если мне придется постоянно загружать организацию и тестировать на ноль, это приведет к сбою в работе моего кода и не оченьDRY.(Так и хочется сказать «СУХОЙ» ...) Я хотел бы загрузить свойство в классе MyUserService, которое заполняется, когда {OrganizationName} включен в URI, и в противном случае выдает исключение WebFaultException.Поскольку это не входит в URI, каков будет лучший способ сделать это?

РЕДАКТИРОВАТЬ:

Для тех, кто может быть заинтересован, вот примерHttpOperationHandler я придумал.Там, кажется, не так много информации, охватывающей это.Я также нашел дополнительную информацию о процессорах , которые будут поставляться с набором WCF Web Api, и похоже, что они справятся с такими вещами лучше заменит HttpOperationHandlers, и кажется, что они могут быть прощеиспользовать.(Это просто для примера, чтобы охватить некоторые вещи, которые мне было трудно найти. Я написал это немного по-другому в своем приложении.)

using Microsoft.ApplicationServer.Http.Dispatcher;   // For HttpOperationHandler
using Microsoft.ApplicationServer.Http.Description;  // For HttpOperationHandlerFactory

public class OrganizationHandler : HttpOperationHandler<string, Organization>
{
    private Repository<Organization> _OrganizationRepository;

    public OrganizationHandler (UnitOfWork Work)
        : base ("OrganizationName")
    {
        _OrganizationRepository = Work.Organizations;
    }

    public override Organization OnHandle (string OrganizationName)
    {
        var Result = _OrganizationRepository
                        .Get (O => O.UrlSafeName.Equals (OrganizationName,
                                                StringComparison.InvariantCultureIgnoreCase));

        if (Result == null)
        {
            throw new WebFaultException<string> ("Organization not found.");
        }

        return Result;
    }
}

public class OrganizationHandlerFactory : HttpOperationHandlerFactory
{
    private UnitOfWork _Work;

    public OrganizationHandlerFactory (UnitOfWork Work)
    {
        _Work = Work;
    }

    protected override Collection<HttpOperationHandler> OnCreateRequestHandlers
        (ServiceEndpoint endpoint, HttpOperationDescription operation)
    {
        var Collection = base.OnCreateRequestHandlers (endpoint, operation);

        if (operation.InputParameters.Any (IP => IP.Type.Equals (typeof (Organization))))
        {
            var Binding = endpoint.Binding as HttpBinding;

            if (Binding != null)
            {
                Collection.Add (new OrganizationHandler (_Work));
            }
        }

        return Collection;
    }
}

А затем подключить это в Global.asax (Я использую Ninject для IoC):

// Add this reference to get the MapServiceRoute<T> extension
using Microsoft.ApplicationServer.Http.Activation;

public class Global : HttpApplication
{
    protected void Application_Start (object sender, EventArgs e)
    {
        var Kernel = BuildKernel ();

        var Config = HttpHostConfiguration.Create ()
            .SetOperationHandlerFactory
                (Kernel.Get (typeof (OrganizationHandlerFactory)) as OrganizationHandlerFactory)
            .SetResourceFactory (new NinjectResourceFactory (Kernel));


        RouteTable.Routes.MapServiceRoute<OrganizationService> ("Organizations", Config);
    }

    protected IKernel BuildKernel ()
    {
        IKernel Kernel = new Ninject.StandardKernel ();

        // Load up the Kernel

        return Kernel;
    }
}

public class NinjectResourceFactory : IResourceFactory
{
    private readonly IKernel _Kernel;

    public NinjectResourceFactory (IKernel Kernel)
    {
        _Kernel = Kernel;
    }

    public object GetInstance (Type serviceType, InstanceContext instanceContext, HttpRequestMessage request)
    {
        return Resolve (serviceType);
    }

    public void ReleaseInstance (InstanceContext instanceContext, object service)
    {
        throw new NotImplementedException ();
    }

    private object Resolve (Type type)
    {
        return _Kernel.Get (type);
    }
}

И вот он у меня в Службе:

[ServiceContract]
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerCall)]
public class OrganizationService
{
    [WebGet (UriTemplate = "{OrganizationName}/Products")]
    public IEnumerable<Product> GetProducts (Organization Organization)
    {
        return Organization.Products;
    }
}

1 Ответ

2 голосов
/ 20 мая 2011

Это именно то, для чего предназначены OperationHandlers. Вы создаете один OperationHandler, который преобразует параметр URI в строго типизированный объект, который можно просто принять в качестве параметра операции.

...