Unable to determine input parameter

Topics: Web Api
Oct 9, 2011 at 9:03 PM

Hello,

I am using the preview 5 and can't seem to create a POST method for my WCF Web API. As per the documentation, I have created the method as follows. As you can see, I am using a method call to 'create' and of the type POST. Ideally, this should work as expected, but for some reason, it gives me the error as shown below. Has anything changed in the new bits? Could it be that the documentation may not have been updated?

 [WebInvoke(UriTemplate = "create", Method = "POST")]
        public long CreateZine(ZineEntity zine, IPrincipal principal)
        {
            long zineId = 0;
            //ZineEntity zine = request.Content.ReadAs();
            if (zine != null && !String.IsNullOrWhiteSpace(zine.ZineName))
            {
                string userId = principal.Identity.Name;
 
                Zine z = new Zine();
                z.ZineName = zine.ZineName;
                z.CreatedByUserId = Int64.Parse(userId);
                z.ZineTags = zine.ZineTags;
                z.ZineDescription = zine.ZineDescription;
                z.IsPrivate = zine.IsPrivate;
 
                zineId = ZineServiceInstance.AddZine(z);
            }
 
            return zineId;
        }

The HttpOperationHandlerFactory is unable to determine the input parameter that should be associated with the request message content for service operation 'CreateZine'. 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, HttpRequestMessage or HttpRequestMessage`1.

Oct 9, 2011 at 9:14 PM

I think I resolved this using the following changes.

  [WebInvoke(UriTemplate = "create", Method = "POST")]
        public long CreateZine(HttpRequestMessage<ZineEntity> request, IPrincipal principal)
        {
            long zineId = 0;
            ZineEntity zine = request.Content.ReadAs();
            if (zine != null && !String.IsNullOrWhiteSpace(zine.ZineName))
            {
                string userId = principal.Identity.Name;
 
                Zine z = new Zine();
                z.ZineName = zine.ZineName;
                z.CreatedByUserId = Int64.Parse(userId);
                z.ZineTags = zine.ZineTags;
                z.ZineDescription = zine.ZineDescription;
                z.IsPrivate = zine.IsPrivate;
 
                zineId = ZineServiceInstance.AddZine(z);
            }
 
            return zineId;
        }

 

I however have another method now, that uses the PUT operation,

  [WebInvoke(UriTemplate = "{id}/restart", Method="PUT")]
        public bool RestartZine(long id, IPrincipal principal)
        {
            bool isClosed = false;
            Check.Argument.IsNotNegativeOrZero(id, "id");
            Check.Argument.IsNotNull(principal, "token");
            string userId = principal.Identity.Name;
            if (!String.IsNullOrWhiteSpace(userId))
            {
                isClosed = ZineServiceInstance.RestartZine(id, Int64.Parse(userId));
            }
 
            return isClosed;
        }

and when I try to run it, I now get the following error. I am wondering why the IPrincipal would work for all of the other GET/POST operations but not in the PUT. Could anything be wrong with the way I am invoking it? The IPrincipal is added via an OperationHandler.

Cannot serialize interface System.Security.Principal.IPrincipal.

Code for the Operation Handler:

protected override IPrincipal OnHandle(HttpRequestMessage input)
        {
            GenericPrincipal principal = null;
            if (input.Headers.Contains(Token))
            {
                foreach (KeyValuePair<stringIEnumerable<string>> header in input.Headers)
                {
                    if (header.Key.ToLowerInvariant() == Token.ToLowerInvariant())
                    {
                        var tokenValue = header.Value.First();
                        // we have a match from header!
                        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(tokenValue);
                        var identity = new GenericIdentity(ticket.Name);
                        principal = new GenericPrincipal(identity, new string[] { });
 
                    }
                }
            }
}
Oct 10, 2011 at 2:54 PM

I would guess that your problem is that your PUT operation does not have a parameter for the request body.  Try adding a HttpRequestMessage parameter and see if the problem goes away.  

Also, you seem to be using PUT in a strange way.  Usually, PUT is used to update an entire resource.   It looks like you are doing something that should be a POST.

Oct 10, 2011 at 7:32 PM

Hello,

Agreed. I originally had it wired up as a POST. I guess I will have to do the POST with the id as a body instead. Let me try that and I will get back to you.

Jan 18, 2012 at 9:28 AM

Same problem not just with PUT but with DELETE also. Just adding HttpRequestMessage parameter starts working. 

[WebInvoke(UriTemplate = "{stuff}/{fileId}")]
public void DeleteFile(HttpRequestMessage request, IMyInterface insertedStuff, string fileId)
{
}

Jan 18, 2012 at 5:13 PM

I've been testing this. And it seems that WebApi only supports a single parameter inside the body.

You need to create a single object that takes in all your post values.

It's an issue on the issue tracker that it does not support wrapped json requests.