Use property injection in Resources

Topics: Web Api
Jan 17, 2011 at 9:45 AM

I've mentioned this before at Glenn's blog.

I think it would be nice to instead of having HttpResponseMessage and/or HttpRequestMessage as part of the method signature, have them as injectable properties of the resource, eg:

    [ServiceContract]
    [Export]
    public class ContactResource
    {
        private readonly IContactRepository repository;

        [ImportingConstructor]
        public ContactResource(IContactRepository repository)
        {
            this.repository = repository;
        }

	public HttpResponseMessage HttpResponseMessage { get; set; }
    	public HttpRequestMessage HttpRequestMessage { get; set; }

        [WebGet(UriTemplate = "{id}")]
        public Contact Get(string id)
        {
            var contact = this.repository.Get(int.Parse(id, CultureInfo.InvariantCulture));
            if (contact == null)
            {
		HttpResponseMessage.StatusCode = HttpStatusCode.NotFound;
		HttpResponseMessage.Content = new StringContent("Contact not found");
            }

            return contact;
        }
}

But this means that Resources would be instantiated per request, which IMO would be much nicer because then we can have eg the IContactRepository be instance based.

Cheers
John

 

Coordinator
Jan 17, 2011 at 10:11 AM

Thanks John.

I actually had a discussion on this.

One idea we came up with was support an interface on the service which if you implement adds those 2 properties. Type type of the properties could maybe be a Current<T> (the name is not important) i.e. Current<HttpResponseMessage>, Current<HttpRequestMesage> where accessing the value would actually get you the correct instance for your current request. This way it could still support both singletons and transient scoped services.

Another option is what you said which is to make it just work for transient.

Anyway, please go file a workitem on this so we (and you) track it. It is something I will definitely add to the backlog.

Regards

Glenn

Coordinator
Jan 17, 2011 at 10:59 AM
Edited Jan 17, 2011 at 11:01 AM

Just realized actually with the new IoC support in the drop you could do this now. Basically to get to the HttpRequest / Response you use extension methods off of the Message class which you get to through the OperationContext. Thus you could do something like

 

public interface IRequestAccessor {
  HttpRequestMessage Request get;
}

public class RequestAccessor : IRequestAccessor {
  public HttpRequestMessage Request { 
    get{
      return OperationContext.Current.RequestContext.Message.ToHttpRequestMessage();
    }
  }
}

public interface IResponseAccessor {
  HttpResponseMessage Response get;
}

public class ResponseAccessor : IResponseAccessor {
  public HttpResponseMessage Response { 
    get{
      return OperationContext.Current.RequestContext.Message.ToHttpResponseMessage();
    }
  }
}

 

So with the above classes, I can now put 2 properties on my service one of type IRequestAccessor and one of IReponseAccessor. Then register the concrete accessors in the IoC so it can inject them. This will work for both singleton and transients.

An alternative option would be to just have the IoC (I think you need a custom resolver in Windsor?) just do the calls to OperationContext directly to support the case you were talking about and just inject the correct Request/Response into a transient service.

Glenn

Jan 17, 2011 at 9:48 PM

I guess I could do what u propose above, but IMO it would be better if the framework does that for me, lazy developer ;)

I think the nicest solution is to make Services transient only.
Why have singleton Services at all, correct me if I'm wrong but I see a WCF Service pretty much the same as a Controller in MVC.

You then don't need this static classes OperationContext.Current :) Easier to test/mock.

Anyway just my 2 cents!

Cheers
John

Coordinator
Jan 17, 2011 at 10:24 PM

We have removed the need for using OperationContent directly in our new bits. You simply work with HttpRequest and HttpResponse. Under the hood however there are still some static APIs that WCF uses. We are however making sure however that going forward you don't "need" to access it directly.

The example I just gave you was a work around with the current bits that would allow you/others to explore / play with the approach.

As far as why we have singleton, the primary reason is shared state. Now once we have proper IoC support baked in, and with MEF in the framework it may be feasible going forward to allow everything to be transient and just get the state injected through services from the container. This is something we will explore.

Glenn

Feb 28, 2011 at 2:50 PM

Hi there Glenn,

I'm running into this same problem.  My services support both rest and soap, therefore I would rather not have HttpRequestMessage / HttpResponseMessage on the service operation signature.  I have not been a fan of that design.

Your example above seems to have issues:

  1. OperationContext.Current.RequestContext.Message.ToHttpResponseMessage();  will never work. In fact, after Reflecting that method I see:
    if ((httpMessage != null) && !httpMessage.IsRequest)
    {
         return httpMessage.GetHttpResponseMessage();
    }
    
    return null; 
  2. I have found that I can get the HttpResponseMessage by doing the following:
    object responseMessage;
    if (OperationContext.Current.RequestContext.RequestMessage.Properties.TryGetValue("HttpMessageProperty", out responseMessage))
    {
        var message = (HttpResponseMessage)responseMessage;
    } 
    1. The problem with the code above is that "HttpMessageProperty" is only available when the dispatcher sends the request to the service operation method.  I need the HttpResponseMessage outside of this scope; particularly the constructor.

I have IoC setup with Unity. I am unsure how to move forward though.  If I register the type IResponseAccessor, how will the HttpResponseMessage property be composed if its not available until the service operation gets called?  Should I wait until the new bits get released with HttpRequest / HttpResponse support?

Jan 10, 2012 at 7:39 PM

Hello,

Is the HttpResponseMessage property still available using the "HttpMessageProperty" described above? I tried this and couldn't find the response object this way. Has this been replaced in Preview 6 with something else?

 

Thanks,

Priya

Jan 11, 2012 at 8:11 AM

>> As far as why we have singleton, the primary reason is shared state.

Singleton == singleton-per-http-request, of course.  I'd call that PerRequest instancing.

Jan 11, 2012 at 9:53 AM

I also agree that adding HttpRequestMessage as a parameter to your API methods isn't a nice design.  Is there any safe way to access this? OperationContext keeps coming up, but everyone seem to agree its not a good idea to use it.

I wonder if it would be possible to create a base class for API classes and use a factory or the config.CreateInstance to populate a request property on it? Off to experiment!

Jan 11, 2012 at 9:58 AM

Hi SiggiG,

Let me know if you have any luck with that. Am experimenting with various other places in the pipeline where I may be able to set response. Am hoping I can at least find a way to set a custom outgoing (or incoming, worst case) property on the OperationContext (or OperationContext.RequestContext.RequestMessage.Properties), where the property is the HttpResponseMessage. Currently experimenting with both, a message handler, as well as a response handler to see if this is doable.

 

Thanks,

Priya

Jan 11, 2012 at 10:32 AM
Edited Jan 11, 2012 at 10:34 AM

This turned out to be rather easy :)  Now I can just write "this.CurrentRequest" in my API methods to access the request.

I'm using a custom HttpConfiguration class I found in a WebAPI sample to use MEF, and simply extended that to flow the context into a base class property if the API class being activated inherits ApiBase.

public class ApiBase
{
    public HttpRequestMessage CurrentRequest { getset; }
}


/// <summary>
/// REST web configuration class for MEF
/// </summary>
public class MefWebConfiguration : WebApiConfiguration
{
    /// <summary>
    /// Initializes a new instance of the MefWebConfiguration class.
    /// </summary>
    /// <param name="container">MEF container</param>
    public MefWebConfiguration(CompositionContainer container)
    {
        CreateInstance = (t, i, m) =>
        {
            var contract = AttributedModelServices.GetContractName(t);
            var identity = AttributedModelServices.GetTypeIdentity(t);
 
            // force non-shared so that every service doesn't need to have a [PartCreationPolicy] attribute.
            var definition = new ContractBasedImportDefinition(contract, identity, nullImportCardinality.ExactlyOne, falsefalseCreationPolicy.NonShared);
            object serviceObject = container.GetExports(definition).First().Value;
            ApiBase serviceApi = serviceObject as ApiBase;
 
            if (serviceApi != null)
            {
                serviceApi.CurrentRequest = m;
                return serviceApi;
            }
            else
            {
                return serviceObject;
            }  
        }; 
    }
}
Jan 11, 2012 at 10:43 AM

How about, in a future drop, requiring that API classes derive from an abstract base class that's part of WCF Web API, and that provides all sorts of info, including the Request and Response objects.... just like MVC controllers?  The System.Web.Mvc.Controller base class provides all sorts of goodness to controllers.

Jan 11, 2012 at 10:47 AM

Nice....now to be able to do it for Response ;-) I need access to the response in a custom operation invoker and if the above pattern works for response as well, I guess I may be able to register response via a ServiceLocator and get it. It still feels like too much trouble. Ideally, I'd love for some outgoing message property to contain the response message - so that I can access the response in places other than just the service (e.g. custom invokers etc.).

 

This is a great start though - thanks!

Jan 11, 2012 at 11:25 AM

Priya, how about putting things in the request.Parameters collection, then using a handler (delegating probably) to map it over to the response? I'm pretty sure the original request is a property on the response object, no?

And Andrew, I totally agree.. I really hope they adapt some of the MVC architecture :)

Jan 11, 2012 at 11:38 AM

In my scenario, I actually want to set status code and response headers, so I need to wait for the operation completion to determine what to do. Plus, what I really need is the actual HttpResponseMessage, so am not sure if the approach above would work.

What I see right now is that anything I set in message properties in an operation handler does not get carried over to my invoker. When I use a delegating handler, if I set a custom property on request message before calling base.SendAsync, that property is available to be (in a really twisted manner though - I have to cast RequestContext.RequestMessage to HttpRequestMessage and then look at HttpRequestMessage's request object's Properties!!). If I set a property in base.SendAsync.ContinueWith... that property is still not visible!

Jan 11, 2012 at 12:32 PM

Can't API methods return HttpResponseMessage<T>? I know it's not as nice as simply returning your resource class directly, but you kind of get the best of both worlds there.  The T is your resource class and the constructor to the message takes it as a param.

Jan 11, 2012 at 1:09 PM
Edited Jan 11, 2012 at 1:09 PM

>> Can't API methods return HttpResponseMessage<T>?

They can.  And if you wanted task-based async, that would presumably become Task<HttpResponseMessage<T>>  :)   But you're right: access to the response is less of an issue than that of access to the request.

Jan 11, 2012 at 6:08 PM
Edited Jan 11, 2012 at 6:10 PM

My requirement is to write the service such that its "endpoint agnostic"...in other words, need it to be generic and can't use WebAPI specific stuff inside the service methods/signatures. I finally figured out a way to make things work (for my scenario at least):

1) My custom invoker changes return type of operation from Task<T> to T. It also sets a custom object on OperationContext.Current.OutgoingMessageProperties. This custom object contains information that is needed to set things like status code/headers on the outgoing response.

2) I've also injected a message inspector. When this message inspector is invoked, it accesses the custom object from OperationContext.Current.OutgoingMessageProperties (and yes, it finds a non null value, thankfully!). Since it has access to the outgoing message object, I use the WebAPI extension method "ToHttpResponseMessage" - if this yields a non null value, I set status code and headers on this (thus taking care of the WebAPI flow). For other cases (i.e. WCF Http endpoint), I can simply set status code and headers by getting the HttpMessageResponseProperty from the message object.

Btw, the way that I access the request object in my custom "hooks" is to look for OperationContext.IncomingMessageProperties["httpRequest"]. I then attempt to convert to an HttpRequestMessage(WebAPI class) by using the "ToHttpRequestMessage" extension method.

Jan 11, 2012 at 6:29 PM
andrewwebb wrote:

How about, in a future drop, requiring that API classes derive from an abstract base class that's part of WCF Web API, and that provides all sorts of info, including the Request and Response objects.... just like MVC controllers?  The System.Web.Mvc.Controller base class provides all sorts of goodness to controllers.


Please don't do this.  Composition over inheritance.  Please don't make me inherit a pattern from MVC's broken architecture.  That "goodness" that you speak of is really not very "good".

Jan 12, 2012 at 9:26 AM

@davidpeden3

You're saying that ASP.NET MVC has a broken architecture?  In what way?  Have you raised this with Microsoft?

Are you saying that ASP.NET MVC has a broken architecture because controllers must inherit from the System.Web.Mvc.Controller base class?  In what way has this hurt you?

The Controller base class provides all sorts of useful information to controllers - inc. the Http context; more specifically the Request and Response objects; plus more.  It provides quite a lot of helper methods, primarily for returning various forms of ActionResult from actions.  We use this stuff extensively.  In what way is this not good?

I can't remember the full composition-over-inheritance quote, but it's stated here as Prefer composition over inheritance as it is more malleable / easy to modify later, but do not use a compose-always approach.  I am happy to have the ASP.NET MVC framework impose inheritance on my controllers: a clear IS-A relationship exists, and that's not going to change, and the base class provides a lot of useful.  I see that a similar approach could work well with API classes in Web API, in that the base class would provide context information and helper methods just like the Controller base class does.  If you wish this to be done via composition, what is your plan? 


Jan 12, 2012 at 11:51 AM

I agree with Andrew here.. I very much like MVC's architecture and would be interested to know whats "not very good" about it :)

Jan 12, 2012 at 7:53 PM
SiggiG wrote:

I agree with Andrew here.. I very much like MVC's architecture and would be interested to know whats "not very good" about it :)


Hey guys, I'm not here to start a flame war and opinions are very much just that, but if you'd like some food for thought, check out the linked blog post below.  There is some good discussion over there.  For the record, I've not personally used FubuMVC but I agree with a lot of Dovetail's opinions on the subject.  Cheers

http://lostechies.com/chadmyers/2011/12/30/sweet-sweet-vindication/