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

本文关键字:参数 Post 方法 文件 cshtml 调用 | 更新日期: 2023-09-27 18:05:26

我已经在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永远不会被调用。我不明白这个问题。谁来帮帮我吧,我被卡在这儿了。

提前感谢。如有任何帮助,不胜感激。

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

让我们做一个小检查。创建一个新的WebApi项目,然后创建一个扩展ApiControllerTestController,然后用你的模型在其中创建一个方法

    [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参数,而不是从post请求体的键/值对中提取。这是因为默认的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中调用全局配置并在所有参数绑定规则之前插入您自己的规则(在结构中的第一个位置),通过调用工厂方法HookupParameterBinding

GlobalConfiguration.Configuration.ParameterBindingRules.Insert(
                0, 
                SimplePostVariableParameterBinding.HookupParameterBinding
);

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

Test
API Description
POST api/Test   
No documentation available.

现在尝试我们的方法,就像他们在blogpost

中尝试的那样
    <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的警告。

您正在发送您的数据作为json对象,但是您的动作参数是简单的类型,它期望在url中找到。试着为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 "";
}