简体   繁体   中英

Create resource at runtime for Web Api controller

My application is multi tenant right now and I have a class that looks up which settings to use based on which tenant is logged in. So I have some code in every controller that essentially looks like this.

[RoutePrefix("api/client/{id})]
public class ReportsController : ApiController
{
    ILogHandler _logHandler = new LogHandler();
    private processor _processor = null;

    public ReportsController(IProcessor Processor)
    {
        _processor = Processor;
    }

    [Route("")]
    [HttpGet]
    [EnableQuery]
    public IHttpActionResult Get(Guid id)
    {
            //Some pseudo code here to get some settings for a client
            var settings = clientSettings(id);

            //investigate the settings
            if(settings.CanDoSomething())
                var qi = _processor.process();
            return Ok(qi);
    }
}

I look up some settings and decide to do some stuff. My problem is every single controller has to do the lookup process but what I'd like to do is have the object already be there and scoped to the correct client.

I tried using Owin middleware and putting the object in the Owin environment but I guess it's to early in the pipeline and I don't know what the value of the Id is in the middleware.

I also have autofac and I've looked into using multitenant but that appears to be more geared toward resolving specific dependencies per tenant or giving tenants access to certain controllers. What I'm after is every tenant gets one of these objects each request but it just needs different setup.

It looks like you've tried to implement this using Owin Middleware. I would think that it would work, but maybe you were looking for an easy way to get the id field, which isn't possible. The problem with Owin middleware is that it works at a really low level: you only get a IDictionary<string, object> which contains all of the information you need to do stuff (in your case, getting the id from the query string; in Web Api's case, getting a whole bunch of stuff). A minor abstraction over this is the OwinMiddleware class; it presents the information from a web request in an object of type IOwinContext . Using Autofac, you can register your middleware with it so it can inject dependencies into it. Given that information, we can create an owin middleware that grabs the id from the query string and sets it on an injected ClientSettings instance:

public class IDParserMiddleware : OwinMiddleware
{
    private ClientSettings Settings;

    public IDParserMiddleware(OwinMiddleware next, ClientSettings settings)
        : base(next)
    {
        Settings = settings;
    }

    public override Task Invoke(IOwinContext context)
    {
        string[] query = context.Request.QueryString.Value.Split('&');
        string id = null;
        foreach (string keyvalue in query)
        {
            if (keyvalue.StartsWith("id=", StringComparison.InvariantCultureIgnoreCase))
            {
                id = keyvalue.Substring(3); // right after "id="
                break;
            }
        }

        Settings.ID = Guid.Parse(id);

        return this.Next.Invoke(context);
    }
}

You can then register this with Owin like so:

IAppBuilder app; // you get this from Owin code like WebApp.Start()
var builder = new ContainerBuilder();
builder.RegisterType<IDParserMiddleware>();
//...
var container = builder.Build();

// This will add the Autofac middleware as well as the middleware
// registered in the container, like IDParserMiddleware
app.UseAutofacMiddleware(container);
// Finally, register Web Api. We do this last so that our middleware
// can run before it and set the ID property.
app.UseAutofacWebApi(config);
app.UseWebApi(config);

More information about that is in this Autofac doc .

Finally, you can have ClientSettings injected into your controller's (or any class's) constructor:

public ReportsController(IProcessor Processor, ClientSettings settings)
{
    _processor = Processor;
    _settings = settings;
}

Due note that I haven't tried this, but from what I've read this should work. Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM