6 Stimmen

WCF Web API UriTemplate-Elemente in mehreren Methoden gefunden

Sagen wir, ich verwende die neue WCF Web API, um einen RESTful-Dienst aufzubauen und habe in meinem Dienst einen Abschnitt der URI, der das Zielressource beschreiben wird, jedoch auf (fast) alle Methoden des Vertrags angewendet wird. Zum Beispiel, wenn ich einen Benutzerdienst habe, der mit eCommerce zu tun hat und so aussehen könnte:

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

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

        if (Organization != null)
        {
            Users = Organization.GetUsers ();
        }
        else
        {
            throw new WebFaultException ("Organisation nicht gefunden.", HttpStatusCode.NotFound);
        }

        return Users;
    }

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

Wenn ich fortlaufend die Organisation laden und auf null prüfen muss, wird mein Code langsamer und nicht sehr DRY sein. (So versucht, DRY auszuschreiben...) Was ich gerne tun würden, ist eine Eigenschaft in der Klasse MyUserService zu laden, die befüllt ist, wenn {OrganizationName} in der URI enthalten ist, und andernfalls eine WebFaultException auslösen. Da dies Teil der URI ist, wie könnte man dies am besten erreichen?

EDIT:

Für diejenigen, die interessiert sein könnten, hier ist ein Beispiel des HttpOperationHandler, den ich entwickelt habe. Es scheint nicht viele Informationen darüber zu geben. Ich habe auch mehr Informationen über Prozessoren gefunden, die mit der WCF Web Api Suite kommen werden und anscheinend besser mit solchen Dingen umgehen werden HttpOperationHandler ersetzen und es scheint, dass sie einfacher zu verwenden sind. (Dies ist nur ein Beispiel, um einige Dinge abzudecken, die ich schwer zu finden fand. Ich habe es in meiner Anwendung etwas anders aufgeschrieben.)

using Microsoft.ApplicationServer.Http.Dispatcher;   // Für HttpOperationHandler
using Microsoft.ApplicationServer.Http.Description;  // Für HttpOperationHandlerFactory

public class OrganizationHandler : HttpOperationHandler
{
    private Repository _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 ("Organisation nicht gefunden.");
        }

        return Result;
    }
}

public class OrganizationHandlerFactory : HttpOperationHandlerFactory
{
    private UnitOfWork _Work;

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

    protected override Collection 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;
    }
}

Und dann, um es in Global.asax zu verknüpfen (ich verwende Ninject für IoC):

// Füge diesen Verweis hinzu, um die Erweiterung MapServiceRoute zu erhalten
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 ("Organisationen", Config);
    }

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

        // Lade den 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);
    }
}

Und hier ist es in meinem Dienst:

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

2voto

Darrel Miller Punkte 133891

Dafür sind OperationHandlers genau da. Sie erstellen einen einzigen OperationHandler, der den URI-Parameter in ein stark typisiertes Objekt umwandelt, das Sie einfach als Parameter der Operation akzeptieren können.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X