Asp.Net实现WebApi跨域 (非MVC)

目前WebApi在使用上大部分都是跟MVC组合的,而且使用起来也确实十分便利。

但有时候我们也需要在WebForm中使用WebApi,二者还是有一定区别的。

首先看下结构

 ①ApiController

 即Controller部分,当然也包含Api的路径也是很重要的。这里面是Api/{function}/{controller}/{action}

看一下Controller里面的内容

using System;
using System.Web.Http;

namespace WebApiTest.Api.Func
{
    public class TestController : ApiController
    {
        [HttpPost]
        public TestModel Post([FromBody]TestModel model)
        {
            model.Name = "Post";
            model.UpdatedOn = DateTime.Now;
            model.Age++;
            return model;
        }
    }
}

 

注意的地方有这么几点:

  • Controller要继承ApiController
  • Action要加上特性 [HttpPost] ,[HttpGet] 。。。如下图
  • 一般情况我们用的都是[HttpPost],这时候参数中就要加特性[FromBody]了
  • 为了能够直接使用请求过来的数据,而不必去转化成对应的实体类,我们需要给参数实体类加特性[Newtonsoft.Json.JsonObject]否则返回的数据会是酱紫的

这是使用的实体类

[Newtonsoft.Json.JsonObject]
public class TestModel
{
    public string Name { set; get; }

    public int Age { set; get; }

    public DateTime UpdatedOn { set; get; }
}

 

 

②跨域处理程序CorsHandler.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Net.Http;
 6 using System.Threading.Tasks;
 7 using System.Threading;
 8 using System.Net;
 9 
10 namespace WebApiTest.Handler
11 {
12     public class CorsHandler : DelegatingHandler
13     {
14         const string Origin = "Origin";
15         const string AccessControlRequestMethod = "Access-Control-Request-Method";
16         const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
17         const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
18         const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
19         const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
20 
21         protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
22         {
23             bool isCorsRequest = request.Headers.Contains(Origin);
24             bool isPreflightRequest = request.Method == HttpMethod.Options;
25             if (isCorsRequest)
26             {
27                 if (isPreflightRequest)
28                 {
29                     return Task.Factory.StartNew<HttpResponseMessage>(() =>
30                     {
31                         HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
32                         response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
33 
34                         string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
35                         if (accessControlRequestMethod != null)
36                         {
37                             response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
38                         }
39 
40                         string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
41                         if (!string.IsNullOrEmpty(requestedHeaders))
42                         {
43                             response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
44                         }
45 
46                         return response;
47                     }, cancellationToken);
48                 }
49                 else
50                 {
51                     return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(t =>
52                     {
53                         HttpResponseMessage resp = t.Result;
54                         resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
55                         return resp;
56                     });
57                 }
58             }
59             else
60             {
61                 return base.SendAsync(request, cancellationToken);
62             }
63         }
64     }
65 }
CorsHandler.cs

 

③Controller配置程序 HttpControllerSelector.cs

 1 using System.Collections.Generic;
 2 using System.Linq;
 3 using System.Net.Http;
 4 using System.Reflection;
 5 using System.Web.Http;
 6 using System.Web.Http.Controllers;
 7 using System.Web.Http.Dispatcher;
 8 
 9 namespace WebApiTest.Handler
10 {
11     public class HttpControllerSelector : DefaultHttpControllerSelector
12     {
13         private HttpConfiguration configuration = null;
14         public HttpControllerSelector(HttpConfiguration configuration)
15             : base(configuration)
16         {
17             this.configuration = configuration;
18             GetControllerMapping();
19         }
20 
21         public override string GetControllerName(HttpRequestMessage request)
22         {
23             object function, c;
24             var routedata = request.GetRouteData();
25 
26             if (routedata.Values.TryGetValue("function", out function) &&
27                 routedata.Values.TryGetValue("controller", out c))
28             {
29                 var item = dict.FirstOrDefault(t => t.Key.Contains(string.Format("{0}.{1}controller", function, c).ToLower()));
30                 if (item.Value != null)
31                 {
32                     return item.Value.ControllerName;
33                 }
34             }
35             return base.GetControllerName(request);
36         }
37 
38         IDictionary<string, HttpControllerDescriptor> dict = new Dictionary<string, HttpControllerDescriptor>();
39         public override IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
40         {
41             var list = Assembly.GetAssembly(this.GetType()).GetTypes().Where(t => t.IsSubclassOf(typeof(ApiController)));
42             foreach (var type in list)
43             {
44                 dict.Add(type.FullName.ToLower(), new HttpControllerDescriptor(this.configuration, type.FullName.ToLower(), type));
45             }
46 
47             return dict;
48         }
49 
50         public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
51         {
52             HttpControllerDescriptor c;
53             var cn = GetControllerName(request);
54             if (dict.TryGetValue(cn, out c))
55             {
56                 return c;
57             }
58             return base.SelectController(request);
59         }
60     }
61 }
HttpControllerSelector.cs

 

④路由注册程序WebApiConfig.cs

 1 using System.Web.Http;
 2 using System.Web.Http.Dispatcher;
 3 
 4 namespace WebApiTest.Handler
 5 {
 6     public static class WebApiConfig
 7     {
 8         public static void Register(HttpConfiguration config)
 9         {
10             // Web API 配置和服务
11             config.Services.Replace(typeof(IHttpControllerSelector), new HttpControllerSelector(config));
12             
13             config.Routes.MapHttpRoute(
14                 name: "Api",
15                 routeTemplate: "api/{function}/{controller}/{action}"
16             );
17         }
18     }
19 }
WebApiConfig.cs

 

⑤Global.asax.cs

在该文件中添加如下代码

        public override void Init()
        {
            this.EndRequest += Global_EndRequest;
            this.BeginRequest += Global_BeginRequest;
            base.Init();
        }

        protected void Application_Start(object sender, EventArgs e)
        {
            GlobalConfiguration.Configuration.MessageHandlers.Add(new CorsHandler());
            WebApiConfig.Register(GlobalConfiguration.Configuration);
        }

 

至此 服务端的配置就基本OK了。

 

调用的地方用如下Ajax就可以了 

$.ajax({
    url: "api/func/Test/Post",
    type: "POST",
    data: {Name:"Ray"},
    dataType:"json",
    success: function (result) {
        console.log(result);
    }
});

 代码下载

 


 

上面讲的是服务端的配置,顺带一提客户端的调用。

但是,如果是在后台调用某个WebApi该如何破呢?

我使用的是Intersoft的CrossLight,用起来也是比较简单。

 

TestModel model = new TestModel();
RestClient c = new RestClient("http://localhost:1234/API/Module/");
RestRequest req = new RestRequest("Function/Do", HttpMethod.POST);
req.RequestFormat = RequestDataFormat.Json;
req.AddBody(model);
var res = c.ExecuteAsync<WebApiModel>(req);
var tmp = JsonConvert.DeserializeObject<WebApiModel<TestModel>>(res.Result.Content).Model;

if (res.Result.Data.HasError) { 
    throw new Exception(res.Result.Data.ErrorMessage); 
}

这里面有个包装的类WebApiModel,是为了更好的传递其他信息(如错误信息),定义如下

using System;

namespace XX
{
    [Newtonsoft.Json.JsonObject]
    [Serializable]
    public class WebApiModel
    {
        public WebApiModel()
        {

        }

        public WebApiModel(object model)
        {
            this.Model = model;
        }

        public object Model { get; set; }

        public bool HasError
        {
            get
            {
                return !string.IsNullOrEmpty(ErrorMessage);
            }
        }
        public string ErrorMessage { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XX
{
    [Newtonsoft.Json.JsonObject]
    [Serializable]
    public class WebApiModel<T>
    {
        public WebApiModel()
        {

        }

        public WebApiModel(T model)
        {
            this.Model = model;
        }

        public T Model { get; set; }

        public bool HasError
        {
            get
            {
                return !string.IsNullOrEmpty(ErrorMessage);
            }
        }
        public string ErrorMessage { get; set; }
    }
}

 

posted @ 2015-07-31 14:09  TiestoRay  阅读(527)  评论(0编辑  收藏  举报