Complex Parameters

Topics: Web Api
Jan 23, 2012 at 10:06 PM

Hello,

I need to pass complex parameters to my service.

1) The client uses simple JSON  it can be jQuery or whatever.

2) Service has a method that accepts an object LoginInfo which is a DataContract.

 

public class AuthService : IAuthService
{
     [WebInvoke(Method = "POST", UriTemplate = "auth")]
     public MyResponseObject Authenticate(LoginInfo loginInfo)
     {
                 ....
     }
}

 

3) IAuthService is a ServiceContract and defines "Authenticate" as operation contract. I need this because I also need to expose this service through nettcp.

Questions:

1) Is there anyway in wcf WEB Api I can pass this object to the operation?

2) what kind of plumbing do I need to perform?

3) I tried declaring a separate method  Authenticate that accepts HttpRequestMessage. It does get into that method without error. But I can't understand why all of the methods are async? Why can't I just read JSon directly?

 

Thanks.

Jan 23, 2012 at 10:22 PM

operations have 3 general parts to them.

1) The input type

2) The output type

3) The output parameter name

You specify the input and output in the generic you inherit from. You specify the parameter output name in the operation constructor, when you call the base constructor.

The input type will be automatically mapped to what is currently available as input parameters. Input parameters are defined by the base operation, and adds anything you specify in your service method. It takes items from the UriTemplate, and the parameters as input arguments.

An example built in accepted input, is HttpRequestMessage. This is automatically added to the input parameters by WebApi.

When you configure a type to be returned, and return it, it can then be used as an input type for following operations, or by inserted into your service call. For instance, if you take in an HttpRequestMessage, and output a IPrincipal. Then if you have an IPrincipal type as an argument, it will be injected there automatically.

If you use a generically named input parameter name, such as "request", and "message", then WebApi might get a little confused. This is what the output parameter name is for. Using the previous example, let's say you want to put IPrincipal type into the "request" parameter name in your service call. Then you would set the outputParameterName to "request". I think you may have to set this no matter what, not sure haven't tested it.

The general principle is that you are given input parameters, then you define additional ones with your service action, which will get added to the routes input parameters. Then you use operation handlers to handle those input parameters, build more input parameters, and then accept those parameters into your service.

Here is a short example:


    public class AuthorizationRequestHandler : HttpOperationHandler<HttpRequestMessage, IPrincipal>
    {

        public AuthorizationRequestHandler()
            : base("user")
{
}


        protected override IPrincipal OnHandle(HttpRequestMessage request)
        {
return new GenericPrincipal(new GenericIdentity("fake"));
}
}



    public class ListingFacadeService
    {
        public void PostJsonp(IPrincipal user)
        {
}
}
Note: didn't test, probably not copy pastable code to run. 

Also, you can see how the HttpMessageRequest gets inserted by doing this:
    public class ListingFacadeService
    {
        public void PostJsonp(HttpRequestMessage request)
        {
}
}

Jan 23, 2012 at 11:22 PM

And from the example above, do I have to register  AuthroizationRequestHandler anywhere?

Thanks.

Jan 23, 2012 at 11:34 PM

Yes you do. I left that part out, how to do that is in the examples... I use structure map to auto map all of mine. Here is a short example of using it in global.asax on app start:

 

            RouteTable.Routes.SetDefaultHttpConfiguration(new AuthenticationHttpConfiguration());




    public class AuthenticationHttpConfiguration : WebApiConfiguration
    {
        public AuthenticationHttpConfiguration()
        {
            var existingFactory = RequestHandlers;
            RequestHandlers = (handlers, endpoint, operation) =>
            {
                if (existingFactory != null)
                {
                    existingFactory(handlers, endpoint, operation);
                }

                 handlers.Add(new AuthorizationRequestHandler());

            };

Jan 23, 2012 at 11:57 PM

The only thing that I have is Microsoft.ApplicationServer.Http.HttpConfiguration. I was able though to register my operation handler through that class. I see that it is being called so I can debug the operation handler an serialize json into the needed object. But my actual method in the service still does not get called. Here is the exception that I am seeing:

The server encountered an error processing the request. The exception message is 'The service operation 'MyOperation' expected a value assignable to type 'MyInputObjecType' for input parameter 'refreshInfo' but received a value of type 'HttpRequestMessage`1'.'. See server logs for more details. The exception stack trace is:

By the way the I am using WebApi.0.6.0

Thanks.

Jan 24, 2012 at 12:04 AM
Edited Jan 24, 2012 at 12:08 AM
WebApiConfiguration comes from the extensions provided with WebApi. 
If you install it via nuget you'll have that class.Hold on a second. 
I was only telling you how to use handlers. 
WebApi will automatically map JSON to your complex object.
That behavior is automatically built in. Just make a handler like this:

public class MyHandler : HttpOperationHandler<LoginInfo, LoginInfo>
    {
        public AuthorizationRequestHandler()
            : base("loginInfo")
{
}

        protected override LoginInfo OnHandle(LoginInfo loginInfo)
        {
return loginInfo;
}
}




Jan 24, 2012 at 12:11 AM

Sorry my above post is formatted retarded, the WYSIWYG is pretty dumb. My above post is also misleading, what I meant is:

WebApi will automatically transform JSON/XML to your complex types. It uses conneg standards for when to do this.

The above example is how you can get an instance of what will be used as the input for your method, so you can modify it before it goes in.

Jan 24, 2012 at 2:22 AM
Edited Jan 24, 2012 at 2:30 AM

Thanks for your help.

But I am still a little lost.

I have the following nuget packages installed right now:

WebApi 0.6.0

When I Inherit HttpOperationHandler it does not have a method T OnHandle(T param) all it has is

T OnHandle(HttpRequestMessage input)

EDIT:

I found the extensions. The Package name is :

WebApi.Enhancements
Jan 24, 2012 at 2:46 AM

digitalpacman, thanks for your help.

It seems to be working now even without custom HttpOperationHandler, after I have installed WebApi.Enhancements.

 

Thanks!