asp.net web api 解决ajax跨站点post请求提交 json 数据问题
一、web api
web api 的 controller ,必须继承 apicontroller:
public class TestController : ApiController
action 可以使用参数绑定直接将 post 请求带的 json 转化为对象,如下:
public string TestMethod([FromBody]PersonInfo pars)
注:要达到这种参数绑定,客户端必须将 设置如下的 content-type 值
Content-Type
application/json; charset=utf-8
二、问题
如果客户端设置content-type 为 application/json ,将导致405 拒绝访问的问题,也就是ajax跨站点请求问题
三、解决方案
1.设置web.config允许跨站点请求
...
2.重写参数绑定类 [FromBody] ,换成自己的 [FromBodyBinder]
四、FromBodyBinder 的实现
FromBodyBinder 类实现
/// /// web api 动态参数绑定模型
/// 解决脚本跨域访问问题
///
public class FromBodyBinder : ParameterBindingAttribute
{
public override System.Web.Http.Controllers.HttpParameterBinding GetBinding(System.Web.Http.Controllers.HttpParameterDescriptor parameter)
{
return new FromBodyHttpParameterBinding(parameter);
}
}
public class FromBodyHttpParameterBinding : HttpParameterBinding
{
public FromBodyHttpParameterBinding(HttpParameterDescriptor des)
: base(des)
{
_parsType = des.ParameterType;
}
private Type _parsType;
private struct AsyncVoid { }
public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
//读取post内容
var task = actionContext.Request.Content.ReadAsStreamAsync();
var content = string.Empty;
var sm = task.Result;
sm.Seek(0, SeekOrigin.Begin);
var bytes = sm.ToByteArray();
content = bytes.ToStr(System.Text.Encoding.UTF8);
var obj = content.ToJsonDeserialize(_parsType);
SetValue(actionContext, obj);
TaskCompletionSourcetcs = new TaskCompletionSource();
tcs.SetResult(default(AsyncVoid));
return tcs.Task;
}
}
用到一个扩展方法 ToJsonDeserialize(),实现如下
public static object ToJsonDeserialize(this string str,Type type)
{
try
{
if (string.IsNullOrWhiteSpace(str))
{
return null;
}
var serialize = new JavaScriptSerializer();
//针对日期序列化时区的转化
str = Regex.Replace(str, @"\\/Date\((-?\d+)\)\\/", match =>
{
var dt = new DateTime(1970, 1, 1);
dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));
dt = dt.ToLocalTime();
return dt.ToString("yyyy-MM-dd HH:mm:ss");
});
return serialize.Deserialize(str, type);
}
catch (Exception ex)
{
return null;
}
}
五、测试代码部分
5.1 服务器代码
public class TestController : ApiController
{
public class PersonInfo
{
public int id { set; get; }
public string name { set; get; }
public DateTime create_time { set; get; }
}
public string TestMethod([FromBodyBinder]PersonInfo pars)
//public string TestMethod([FromBody]PersonInfo pars) web api 的写法
{
var result = new
{
receive_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") ,
data=pars
};
return result.ToJsonSerialize();
}
}
5.2客户端写法
页面标题