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; }
    }
}
时间: 2024-10-11 07:01:25

Asp.Net实现WebApi跨域 (非MVC)的相关文章

C#进阶系列——WebApi 跨域问题解决方案:CORS

from:http://www.cnblogs.com/landeanfen/p/5177176.html 阅读目录 一.跨域问题的由来 二.跨域问题解决原理 三.跨域问题解决细节 1.场景描述 2.场景测试 四.总结 正文 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题.本篇主要从实例的角度分享下CORS解决跨域问题一些细节. WebApi系列文章 C#进阶系列--WebApi接口测试工具:WebApiTestClient C#进阶系列

WebApi 跨域问题解决方案:CORS

注:本文为个人学习摘录,原文地址:http://www.cnblogs.com/landeanfen/p/5177176.html 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题.本篇主要从实例的角度分享下CORS解决跨域问题一些细节. 一.跨域问题的由来 同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容. 正是由于这个原因,我们不同项目之间的调用就会被浏览器阻止.

WebAPI跨域处理

WebApi2跨域问题 一.跨域问题产生的原因:同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能. 现在所有支持JavaScript 的浏览器都会使用这个策略. 所谓同源是指,域名,协议,端口相同. 当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面 当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的, 即检查是否同源,只有和百度同源的脚本才会被执行. 由于同源策略的限制,JavaScript就产生了跨域的问题. 参考:同源

ASP.NET中Cookie跨域的问题及解决代码

ASP.NET中Cookie跨域的问题及解决代码 http://www.liyumei.net.cn/post/share18.html Cookies揭秘  http://www.cnblogs.com/zhangziqiu/archive/2009/08/06/cookies-javascript-aspnet.html 最近在项目开发中遇到一个很棘手的问题,一个用户在顶级域名登录后,跳转到自己所拥有的二级域名下管理二级网站时,cookie丢失了,一直找解决办法找了整整两天,百度谷歌一大堆,

关于WebAPI跨域踩到的一点坑

最近在尝试前后端分离的WebAPI+AngularJS方案,在率先处理授权的时候,踩到了一点WebAPI跨域的坑,其实严格意义上来说也不算是坑吧,只是我自己对WebAPI不熟悉而已,这里我与大家分享一下. 先说一下我这边遇到的情况: 我是在做登录功能,使用的是微软的OWin提供的组件来实现 对于WebAPI跨域,你如果去百度或者谷歌,基本上会有以下两种答案: 一.在Web.config增加配置 在Web.config中system.webServer节点下面,增加配置项,设置输出的http he

传统Webform 跨域调用 MVC 4 Web API实现分布式 无法解析 解决方案

前言: 正好在大概7月1日学习一份kendo ui的资料时发现一共5个章节,前3个章节都是用来讲Web API了,既然都已经看了索性就尝试一下,也不做深层次了解了,于是查阅了一些资料尝试写一个基于MVC 4 的WebAPI Demo. 正文: 下文简略介绍服务端的部分实现: 创建一个MVC4 基本项目,也就是不需要自己创建一些基本的注册绑定了. 直接新建一个Controller以及一个Model,如下所示: UserModel.cs 1 public class UserModel 2 { 3

WebApi跨域方案(转)

一.跨域问题的由来 同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容.   正是由于这个原因,我们不同项目之间的调用就会被浏览器阻止.比如我们最常见的场景:WebApi作为数据服务层,它是一个单独的项目,我们的MVC项目作为Web的显示层,这个时候我们的MVC里面就需要调用WebApi里面的接口取数据展现在页面上.因为我们的WebApi和MVC是两个不同的项目,所以运行起来之后就存在上面说的跨域的问题. 二.跨域问题解决原

ASP.NET Web API 跨域访问(CORS)要注意的地方

一.客户端用JSONP请求数据 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的: {"YourSignature": "嫁人要嫁程序员,钱多话少死得早"} 然而,JSONP请求期望得到这样的JSON: jQuery123456({"YourSignature": "嫁人要嫁程序员,钱多话少死得早"}) 所以我们需要对WebAPI做拓展,让它支持这

asp.net中WebResponse 跨域访问示例

前两天,一个朋友让我帮他写这样一个程序:在asp.net里面访问asp的页面,把数据提交对方的数据库后,根据返回的值(返回值为:OK或ERROR),如果为OK再把填入本地数据库.当时,想当然,觉得很简单,用js的xmlhttp ,如果根据response 的值是“OK”就执行提交本地数据库.很快写完发过去,让朋友试试,一试发现不行,后来一问,原来是跨域访问,我给忽略了,于是让朋友把asp改成web service,可朋友说程序是合作公司做的,只会asp,不会用web service ,狂晕ing