在cshtml文件中调用具有多个参数的Post方法

时间:2015-07-30 09:07:27

标签: c# jquery asp.net-mvc razor asp.net-web-api

我在MVC WebApi中声明了一个方法:

[Route("api/User/LoginUser")]
public string PostLogin(string email, string password, string authkey)
{
//  Do Something
    return "";
}

现在在用于测试目的的cshtml文件中,我将方法调用为:

function LoginUser() {
        $.ajax({
            url: baseUrl + "api/User/LoginUser",
            type: "Post",
            contentType: 'application/json; charset=utf-8',
            data: JSON.stringify({ email: "xyz@gmail.com", password: "password", authkey: "1234" }),
            dataType: 'json',
            success: function (data) {
                // Do Soemthing
            },
            fail: function (data) {
                // Failed
            }
        });
    }

但api从未被调用过。我没有遇到问题。请有人帮助我,我在这里遇到了很大的困难。

提前完成。任何形式的帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

让我们做一点检查。创建新的WebApi项目,然后创建一个TestController扩展ApiController,然后在其中创建一个包含模型的方法

    [HttpPost]
    public string SomeThing(string name, string age)
    {
        return "smth";
    }

现在编译应用程序并打开localhost/Help

有关于可用方法的文档。我们的Test控制器也有记录。让我们看看那里有什么:

Test
API Description
POST api/Test?name={name}&age={age} 

No documentation available.

似乎多个参数自动映射为GET参数,而不是从后请求体中的键/值对中提取。这是因为默认HttpParameterBinding,如果您想要更改它,则需要对其进行扩展,覆盖某些内容并告知您的应用使用精心设计的HttpParameterBinding覆盖。

幸运的是,有关于如何创建自己的参数绑定的博客文章(http://weblog.west-wind.com/posts/2012/Sep/11/Passing-multiple-simple-POST-Values-to-ASPNET-Web-API

给予博客作者的所有信用,如果链接被破坏,我将粘贴一些代码。

在应用程序的某处创建一个扩展HttpParameterBinding

的类
public class SimplePostVariableParameterBinding : HttpParameterBinding
{
    private const string MultipleBodyParameters = "MultipleBodyParameters";

    public SimplePostVariableParameterBinding(HttpParameterDescriptor descriptor)
        : base(descriptor)
    {
    }

    /// <summary>
    /// Check for simple binding parameters in POST data. Bind POST
    /// data as well as query string data
    /// </summary>
    /// <param name="metadataProvider"></param>
    /// <param name="actionContext"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
                                                HttpActionContext actionContext,
                                                CancellationToken cancellationToken)
    {               
        string stringValue = null;

        NameValueCollection col = TryReadBody(actionContext.Request);
        if (col != null)
            stringValue = col[Descriptor.ParameterName];

        // try reading query string if we have no POST/PUT match
        if (stringValue == null)
        {
            var query = actionContext.Request.GetQueryNameValuePairs();
            if (query != null)
            {
                var matches = query.Where(kv => kv.Key.ToLower() == Descriptor.ParameterName.ToLower());
                if (matches.Count() > 0)
                    stringValue = matches.First().Value;
            }
        }

        object value = StringToType(stringValue);

        // Set the binding result here
        SetValue(actionContext, value);

        // now, we can return a completed task with no result
        TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>();
        tcs.SetResult(default(AsyncVoid));
        return tcs.Task;
    }


    /// <summary>
    /// Method that implements parameter binding hookup to the global configuration object's
    /// ParameterBindingRules collection delegate.
    /// 
    /// This routine filters based on POST/PUT method status and simple parameter
    /// types.
    /// </summary>
    /// <example>
    /// GlobalConfiguration.Configuration.
    ///       .ParameterBindingRules
    ///       .Insert(0,SimplePostVariableParameterBinding.HookupParameterBinding);
    /// </example>    
    /// <param name="descriptor"></param>
    /// <returns></returns>
    public static HttpParameterBinding HookupParameterBinding(HttpParameterDescriptor descriptor)
    {
        var supportedMethods = descriptor.ActionDescriptor.SupportedHttpMethods;      

        // Only apply this binder on POST and PUT operations
        if (supportedMethods.Contains(HttpMethod.Post) ||
            supportedMethods.Contains(HttpMethod.Put))
        {
            var supportedTypes = new Type[] { typeof(string), 
                                                typeof(int), 
                                                typeof(decimal), 
                                                typeof(double), 
                                                typeof(bool),
                                                typeof(DateTime),
                                                typeof(byte[])
                                            };            

            if (supportedTypes.Where(typ => typ == descriptor.ParameterType).Count() > 0)
                return new SimplePostVariableParameterBinding(descriptor);
        }

        return null;
    }


    private object StringToType(string stringValue)
    {
        object value = null;

        if (stringValue == null)
            value = null;
        else if (Descriptor.ParameterType == typeof(string))
            value = stringValue;
        else if (Descriptor.ParameterType == typeof(int))
            value = int.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(Int32))
            value = Int32.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(Int64))
            value = Int64.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(decimal))
            value = decimal.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(double))
            value = double.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(DateTime))
            value = DateTime.Parse(stringValue, CultureInfo.CurrentCulture);
        else if (Descriptor.ParameterType == typeof(bool))
        {
            value = false;
            if (stringValue == "true" || stringValue == "on" || stringValue == "1")
                value = true;
        }
        else
            value = stringValue;

        return value;
    }

    /// <summary>
    /// Read and cache the request body
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    private NameValueCollection TryReadBody(HttpRequestMessage request)
    {
       object result = null;

        // try to read out of cache first
        if (!request.Properties.TryGetValue(MultipleBodyParameters, out result))
        {
            var contentType = request.Content.Headers.ContentType;

            // only read if there's content and it's form data
            if (contentType == null || contentType.MediaType != "application/x-www-form-urlencoded")
            {
                // Nope no data
                result = null;
            }
            else
            {
                // parsing the string like firstname=Hongmei&lastname=ASDASD            
                result = request.Content.ReadAsFormDataAsync().Result;
            }

            request.Properties.Add(MultipleBodyParameters, result);            
        }

        return result as NameValueCollection;
    }

    private struct AsyncVoid
    {
    }
}

然后在Startup.cs中调用全局配置并在所有param绑定规则之前插入,通过调用工厂方法HookupParameterBinding

自己的规则(在结构中的第一个位置)
GlobalConfiguration.Configuration.ParameterBindingRules.Insert(
                0, 
                SimplePostVariableParameterBinding.HookupParameterBinding
);

现在重新编译应用程序并再次检查帮助页面。您现在控制器不要求您将方法签名作为GET请求发送

Test
API Description
POST api/Test   

No documentation available.

现在尝试我们的方法,就像他们在博客中尝试的那样

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<form>
    Name: <input type="text" id="name" value="ggg" />
    Age: <input type="text" id="age" value="ddd" />

    <input type="button" id="btnSend" value="Send" />
</form>

<script type="text/javascript">
    $("#btnSend").click(function () {
        $.ajax({
            url: "http://localhost:50931/api/Test",
            type: "POST",
            data: {
                name: $("#name").val(),
                age: $("#age").val()
            },
            success: function(response) {
                alert(response)
            }
        });
    });
</script>

点击按钮,我们收到一条提示smth的警告,因为我们“返回”smth“

如果我们打开freibug控制台并跟踪我们通过jquery发送的内容,我们将看到

POST http://localhost:50931/api/Test

200 OK
        2ms 
jquery-1.10.2.js (line 8720)
HeadersPostResponseJSONCookies
Parametersapplication/x-www-form-urlencodedDo not sort
age 
ddd
name    
ggg

作为替代方案,我们可以使用简单的json序列化,因此我们可以使方法签名期望JObject

using Newtonsoft.Json.Linq;

public class TestController : ApiController
{
    [HttpPost]
    public string SomeThing(JObject obj)
    {
        return obj["name"] + " bla " + obj["age"];
    }
}

如果我们针对此方法执行POST,就像上面的HTML一样,我们会收到ddd bla ggg的提醒。

答案 1 :(得分:0)

您将数据作为json对象发送,但您的操作参数是预期在网址中找到的简单类型。 尝试为POST创建一个复杂的对象。

public class LoginUser
{
    public string email { get; set; }
    public string password{ get; set; }
    public string authkey{ get; set; }
}

并将您的Api操作更改为

[Route("api/User/LoginUser")]
public string PostLogin(LoginUser user)
{
    string email - user.email;
    string password- user.email;
    string authkey- user.email;
    return "";
}