Error: The HttpOperationHandlerFactory is unable to determine the input parameter

Topics: Web Api
May 4, 2011 at 10:20 PM

I have following resource defined:

    [ServiceContract]
    public class MyResource
    {
        [WebInvoke(UriTemplate = "/initiate", Method = "POST")]
        public TransactionInfo Initiate(PurchaseInformation info, HttpRequestMessage req)
        {
            TransactionInfo txnInfo = new TransactionInfo()
            {
                TransactionId = 1,
                TransactionCode = "ABCD"
            };

            return txnInfo;
        }
    }

When I write client code to post purchase information, I get following error:

The HttpOperationHandlerFactory is unable to determine the input parameter that should be associated with the request message content for service operation 'Initiate'. If the operation does not expect content in the request message use the HTTP GET method with the operation. Otherwise, ensure that one input parameter either has it's IsContentParameter property set to 'True' or is a type that is assignable to one of the following: HttpContent, ObjectContent`1,

I change the operation definition to following:

        public TransactionInfo Initiate(PurchaseInformation info)
        {
            TransactionInfo txnInfo = new TransactionInfo()
            {
                TransactionId = 1,
                TransactionCode = "ABCD"
            };

            return txnInfo;
        }

It works fine as expected. How can I make a successful call with first definition (with HttpRequestMessage) of the service operation? What exactly does the error message mean from theoritical point of view? Am I missing any thing obvious?

Thanks.

May 4, 2011 at 11:25 PM

When you want pass a strongly typed object and receive the HttpRequestMessage you can use the HttpRequestMessage<T> class.

 

[ServiceContract]
    public class MyResource
    {
        [WebInvoke(UriTemplate = "/initiate", Method = "POST")]
        public TransactionInfo Initiate(HttpRequestMessage<PurchaseInformation> req)
        {

            PurchaseInformation purchaseInfo = req.Content.ReadAs();
            TransactionInfo txnInfo = new TransactionInfo()
            {
                TransactionId = 1,
                TransactionCode = "ABCD"
            };

            return txnInfo;
        }
    }

I think the error message is telling you it is upset because you are asking it to put the request body in two different places.  An alternative that I believe would work is,

        [WebInvoke(UriTemplate = "/initiate", Method = "POST")]
        public TransactionInfo Initiate(PurchaseInformationinfo, HttpRequestHeaders requestHeaders) {

May 5, 2011 at 1:29 AM

Thanks for the reply.

I tried both methods and neither is working. In the first method, it is erroring with XmlException is being thrown related to Root element. It is being raised in XmlMediaTypeFormatter.OnReadFromStream method. I checked the position of the supplied stream in this method. It is not yet zero on the entry to this method. Obviously something else is reading it before this method is invoked. Not sure, if this feature is fully implemented in the latest preview bits.

Are there any other alternatives to make this work?

 

May 5, 2011 at 2:18 AM

To my knowledge this is working.  I'll try it myself and let you know.   Are you calling this from a unit test?  Or from something like Fiddler?

May 5, 2011 at 5:53 AM

I tried POSTing both XML and Json using an operation contract that had a strong type as an input parameter and it worked fine.  The only think you must remember to do, which I was forgetting initially is to set the Content-Type header on the request or the request pipeline does not know how to deserialize the content.

May 5, 2011 at 1:22 PM

how about something much simpler like an array of strings?

May 5, 2011 at 5:33 PM

Once I made following adjustment to the code, everything is working fine:

[ServiceContract]
    public class MyResource
    {
        [WebInvoke(UriTemplate = "/initiate", Method = "POST")]
        public TransactionInfo Initiate(HttpRequestMessage<PurchaseInformation> req)
        {

            req.Content.ContentReadStream.Position = 0;

            PurchaseInformation purchaseInfo = req.Content.ReadAs();
            TransactionInfo txnInfo = new TransactionInfo()
            {
                TransactionId = 1,
                TransactionCode = "ABCD"
            };

            return txnInfo;
        }
    }

Thank you for your help.

May 5, 2011 at 6:41 PM

You really should not have to do this.  Do you have any custom OperationHandlers setup?

May 5, 2011 at 7:59 PM

No. But I started having other issues with xml content. The plumbing started adding xml declaration at the end of the request again with same object as the request. As shown below:

Operation declaration:

        public Transaction Initiate(HttpRequestMessage<Transaction> req)
        {
            string request = req.Content.ReadAsString();
            ...

        }

The request now shows following:

 <?xml version="1.0" encoding="utf-8"?><Transaction><TransactionId>0</TransactionId><PurchaseRole>Payer</PurchaseRole><Amount>50</Amount><AmountType>Express</AmountType><AmountDeviationPercent>10</AmountDeviationPercent><PurchasedItems><PurchasedItem><PurchasedItemId>1</PurchasedItemId><Name>Soap</Name><ItemType>Bath</ItemType><Price>2</Price></PurchasedItem></PurchasedItems><IncludeBarcodeInfo>false</IncludeBarcodeInfo></Transaction><?xml version="1.0" encoding="utf-8"?><Transaction p1:nil="true" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance" />

Interestingly the json content works fine without any problems!

Weird!

May 5, 2011 at 11:19 PM

I think in your sample code, you should be able to do:

Transaction transaction = req.Content.ReadAs<Contract>();

If you're passing in a typed request, I do not think it is correct to try to read the content as a string (unless, of course, it is HttpRequestMessage<string>).

May 6, 2011 at 12:09 AM

Agree. The problem is that it is blowing up in xml serializer somewhere. This tells me that it is trying to process the above string as is, which will definitely be a problem for the xml serializer.

May 6, 2011 at 3:11 PM

Make sure your client is sending the right Accept header.