• 瞎折腾之Mvc WebApi的使用以及跨域问题


    在公司经常会用到调用接口的情况,但是一直是用的webservice,我感觉真是太笨重了。虽然某些人感觉用的很爽、非常爽。比如说:公司在开发的时候需要对接另一组的接口,然后就只能是指定端口和ip到他的电脑。其中各种问题,他在修改代码,或者电脑不开启,我们这边都不能进行开发了。我希望下次能用上api

    然后就是,园子里好多api的文章都没有降到跨域的解决方案,演示项目创建成功了,然后就在当前项目的调取成功了api的接口方法。就成功了?逗我们玩呢?没有错、就是在逗我们玩。

    接下来让我们进入webapi

    创建WebApi项目

    这里我已经提前创建好了2个站点,一个api和一个mvc项目。然后分别添加到IIS(这里的iis8),如果不知道怎么添加到iis我就简单描述一下。

    打开iis管理器-->网站,右键添加网站-->网站名称随意取名、物理路径选择你项目web所在路径-->然后是应用程序池,最好选择DefaultAppPool-->主机名:取一个自己网站的名字(注意:这里的名字是需要配置host文件的)-->确定

    然后就是配置host文件了,C:WindowsSystem32Driversetc 路径下面的hosts文件,有些电脑是可以直接修改的,如果不可以就复制到桌面修改了再放进去这个文件夹下面即可。配置如下:

    127.0.0.1   myWeb.loca/
    127.0.0.1   myApi.loca/

    我的web主机名:myWeb.loca/(跟配置iis给自己网站取名是一样的)

    我的api主机名:myApi.loca/(跟配置iis给自己网站取名是一样的)

    浏览器访问的时候在前面记得加上:http://myWeb.loca/

    开启api路程

    接下来我开始实施工程了。上面一系列的配置已经准备好。

    首先我就要修改webapi的路由,因为默认的是根据参数的传递来决定访问的方法的。这里我设置成mvc的习惯 App_Start-->WebApiConfig.cs

               config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );    

    然后就是已经写好了的api一个方法

     public class ValuesController : ApiController
        {
            private LX.EFOPT.BLL.IBLL.IUser_InfoBLL User_InfoBLL = new User_InfoBLL();
    
            // GET api/values
            public string GetList()
            {
                List<LX.EFOPT.Model.User_Info> modelUser_InfoList = User_InfoBLL.GetUser_InfoList();
    
                string jsonList = JsonUtils.SerializeToJson(modelUser_InfoList);
    
                return JsonUtils.SerializeToJson(new
                {
                    code = "1",
                    msg = "success",
                    data = modelUser_InfoList
                });
            }
    View Code

    然后呢,我们直接在浏览器访问这个api,验证一下我们的数据是否正确输出,直接访问地址:http://myapi.loca/api/values/GetList

    结果显示如下:

    哎呀妈呀,好开森!当然,这还没有完呢,我没有逗你们玩。接下来,我在myWeb.loca/ 这个web站点访问api。走你~

    同样、我已经在web站点建好了一个user控制器、马上建一个apitest的页面

    <input type="button" id="getlist" value="get数据list" /><br />
        function getlist() {
            var url = "http://myapi.loca/api/values/GetList?callback=?";

          console.log("getJSON:start");
          $.getJSON(url,
          function (data) {
            //处理data数据
            console.log("getJSON:end");
            console.log($.parseJSON(data));
          });

        }

    返回结果:没有执行回调函数

    这个问题第一次会很难找到原因。ajax已经执行而且状态是200,在Network里面还可以看见Response返回的字符串。总之、在$.getJSON的回调函数里面没有执行返回结果。

    第一种解决方案

    1、我们先来一个低成本(低版本)的解决方案。因为此版本只需要Framework 4.0就可以了

    我们在App_Start文件夹下面添加一个JsonCallbackAttribute属性类,让它继承自ActionFilterAttribute。注意看代码,这段代码是根据传过来的参数callback判断的

     public class JsonCallbackAttribute : ActionFilterAttribute
        {
            private const string CallbackQueryParameter = "callback";
            public override void OnActionExecuted(HttpActionExecutedContext context)
            {
                var callback = string.Empty;
    
                if (IsJsonp(out callback))
                {
                    var jsonBuilder = new StringBuilder(callback);
    
                    jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result);
    
                    context.Response.Content = new StringContent(jsonBuilder.ToString());
                }
    
                base.OnActionExecuted(context);
            }
    
            private bool IsJsonp(out string callback)
            {
                callback = HttpContext.Current.Request.QueryString[CallbackQueryParameter];
                return !string.IsNullOrEmpty(callback);
            }
        }
    View Code

    然后把这个 [JsonCallback]属性加到api方法上面或者控制器上面都可以。

          [JsonCallback]
          public class ValuesController : ApiController
          //或者
           [JsonCallback]
            public string GetList()
            {
            }

    接下来我们再看看执行ajax之后的结果是怎么样呢?

    加了[JsonCallback]结果显示:很明显结果显示回调成功了。而且还打印出了json,此刻代表着我们的方案成功了。哎哟、不错哦~

    第二种解决方案

    这个方法需要的成本可就高点了,至少是Framework 4.5以上的版本才行。怕什么。装一个就可以了呗。是、但是一般的服务器上面有4.5的吗?反正我们的就没有

    第一步:还是在api站点的App_Start文件夹下面添加一个JsonpMediaTypeFormatter类

         public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
        {
            public string Callback { get; private set; }
    
            public JsonpMediaTypeFormatter(string callback = null)
            {
                this.Callback = callback;
            }
            public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, System.Net.TransportContext transportContext)
            {
                if (string.IsNullOrEmpty(this.Callback))
                {
                    return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
                }
                try
                {
                    this.WriteToStream(type, value, writeStream, content);
                    return Task.FromResult<AsyncVoid>(new AsyncVoid());
                }
                catch (Exception exception)
                {
                    TaskCompletionSource<AsyncVoid> source = new TaskCompletionSource<AsyncVoid>();
                    source.SetException(exception);
                    return source.Task;
                }
            }
    
            private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
            {
                JsonSerializer serializer = JsonSerializer.Create(this.SerializerSettings);
                using (StreamWriter streamWriter = new StreamWriter(writeStream, this.SupportedEncodings.First()))
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter) { CloseOutput = false })
                {
                    jsonTextWriter.WriteRaw(this.Callback + "(");
                    serializer.Serialize(jsonTextWriter, value);
                    jsonTextWriter.WriteRaw(")");
                }
            }
    
            public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
            {
                if (request.Method != HttpMethod.Get)
                {
                    return this;
                }
                string callback;
                if (request.GetQueryNameValuePairs().ToDictionary(pair => pair.Key,
                     pair => pair.Value).TryGetValue("callback", out callback))
                {
                    return new JsonpMediaTypeFormatter(callback);
                }
                return this;
            }
        }
    View Code

    第二步:在Global.asax的Application_Start里面注册一下全局

    GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter());

    其实还有第三第四中解决方案的、只是我测试还没有成功,不知道具体是什么原因。

    总结

    这里解决了ajax get获取数据的方法,至于post嘛、客户端自己ajax先提交到自己的Handler.ashx或者控制器嘛。然后用httppost去提交api的接口也是一样的。

    谢谢!希望各位大神能留下一点建议和意见,本人才开始写文章。给点鼓励。

    感谢大神的文章

    参考文章:http://www.cnblogs.com/artech/p/cors-4-asp-net-web-api-03.html

    http://stackoverflow.com/questions/9421312/jsonp-with-asp-net-web-api/18206518#18206518

    原文出自:http://www.cnblogs.com/lxsweat/

  • 相关阅读:
    Javascript的异步和回调
    JS-使用工厂方法创建对象
    PHPUnit使用教程——PHP环境变量+x-debug+composer+phpunit配置安装(超详细!)
    JQuery 纵向二级菜单与对齐方式
    图像映射<map>、<area>
    打开另一个窗口
    多行文本省略号
    replace 正则
    jquery each用法
    li前面的原点或者方的样式修改html中列表项li所显示的圆点的颜色?,以及相关样式的设定
  • 原文地址:https://www.cnblogs.com/lxsweat/p/4402172.html
Copyright © 2020-2023  润新知