zoukankan      html  css  js  c++  java
  • 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; }
        }
    }
  • 相关阅读:
    【Javascript】JS单例模式的简单实现
    【Javascript】Javascript中如何判断变量是数组类型
    买卖股票的最佳时机 II
    只出现一次的数字
    删除排序数组中的重复项
    两数之和
    Android系统中Fastboot和Recovery所扮演的角色。
    虚函数、纯虚函数、抽象类、接口 (Java_C++_C#)
    关于cmd中执行命令路径包含空格的解决办法
    Windows API 编程学习记录<三>
  • 原文地址:https://www.cnblogs.com/TiestoRay/p/4583740.html
Copyright © 2011-2022 走看看