سؤال

I'm currently writing a little application consisting of a mvc web api server and mvc 4 client, I've faced a problem, that is eating my mind for several days already.

I have a ContactsController, that contains:

[HttpPost]
    public ActionResult AddContact(ContactModel model, HttpPostedFileBase image)
    {
        return ActionWrapper(() =>
        {
            if (model.InitializeFromCookie())
            {
                if (image != null)
                {
                    model.ImageMimeType = image.ContentType;
                    model.Picture = new byte[image.ContentLength];
                    image.InputStream.Read(model.Picture, 0, image.ContentLength);
                }

                PostObject("api/contacts/postcontact", model);
                RefreshCookie();
                return RedirectToAction("Contacts", "Contacts");
            }

            else
            {
                return JsonRedirectResult(Url.Action("Login", "Users"));
            }
        });
    }

Model is derived from AuthorizationContent. The post object method:

[NonAction]
        protected object PostObject(string apiUrl, object obj, object additionalData = null)
        {
            var query = additionalData != null ? additionalData.GetQueryString() : string.Empty;
            apiUrl += query;
            var action = _client.PostAsJsonAsync(apiUrl, obj);
            action.Wait();

            if (!action.Result.IsSuccessStatusCode)
            {
                var code = action.Result.StatusCode;
                var error = action.Result.ReasonPhrase;
                throw new ServerSideException(code, error);
            }

            else
            {
                return action.Result.Content.ReadAsAsync<object>().Result;
            }
        }

The method is about to call webapi controllers' method:

[AuthorizedOnly, HttpPost]
    public void PostContact([FromBody]AuthorizationContent item, User authorizedUser)
    {
        var realItem = Mapper.Map<ContactModel, Contact>((ContactModel) item);
        _contactService.AddContact(authorizedUser, realItem);
    }

The filter:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
class AuthorizedOnly : ActionFilterAttribute
{
    private ISessionService _sessionService;
    private Session _userSession;

    public ISessionService SessionService
    {
        get { return _sessionService ?? (_sessionService = NinjectWebCommon.Kernel.Get<ISessionService>()); }
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var auth = actionContext.ActionArguments.Values.FirstOrDefault() as AuthorizationContent;

        if (auth == null)
        {
            throw new UnauthorizedException();
        }

        else
        {
            var user = SessionService.GetMemberBySessionCredentials(auth.Token, auth.UserName);
            _userSession = user.Session;

            if (SessionService.IsSessionValid(_userSession))
            {
                actionContext.ActionArguments["authorizedUser"] = user;
                base.OnActionExecuting(actionContext);
            }

            else
            {
                throw new UnauthorizedException();
            }
        }
    }

The code works just fine for get actions, but when i am trying to do the post as shown above i'm always getting a server side exception stating

{StatusCode: 400, ReasonPhrase:

'Can't bind multiple parameters ('item' and 'authorizedUser') to the request's content.', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Content-Type: text/plain; charset=utf-8 } }

The question - how can i state that authorizedUser will come from filter and model binder should NOT look for it in requests content? Sorry for my bad english and thank you beforehand!

هل كانت مفيدة؟

المحلول

You can just have an empty parameter binding that does nothing other than saying that it will not read from body. Refer to this blog post on why only one parameter can read the body in web API. You can register the parameter binding either on the configuration globally or define an attribute for it. Sample code follows for the parameter binding,

public class EmptyParameterBinding : HttpParameterBinding
{
    public EmptyParameterBinding(HttpParameterDescriptor descriptor)
        : base(descriptor)
    {
    }

    public override bool WillReadBody
    {
        get
        {
            return false;
        }
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        return Task.FromResult(0);
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top