瞎折騰之Mvc WebApi的使用以及跨域問題

在公司常常會用到調用接口的狀況,可是一直是用的webservice,我感受真是太笨重了。雖然某些人感受用的很爽、很是爽。好比說:公司在開發的時候須要對接另外一組的接口,而後就只能是指定端口和ip到他的電腦。其中各類問題,他在修改代碼,或者電腦不開啓,咱們這邊都不能進行開發了。我但願下次能用上apihtml

而後就是,園子裏好多api的文章都沒有降到跨域的解決方案,演示項目建立成功了,而後就在當前項目的調取成功了api的接口方法。就成功了?逗咱們玩呢?沒有錯、就是在逗咱們玩。web

接下來讓咱們進入webapi

建立WebApi項目

這裏我已經提早建立好了2個站點,一個api和一個mvc項目。而後分別添加到IIS(這裏的iis8),若是不知道怎麼添加到iis我就簡單描述一下。ajax

打開iis管理器-->網站,右鍵添加網站-->網站名稱隨意取名、物理路徑選擇你項目web所在路徑-->而後是應用程序池,最好選擇DefaultAppPool-->主機名:取一個本身網站的名字(注意:這裏的名字是須要配置host文件的)-->肯定json

而後就是配置host文件了,C:\Windows\System32\Drivers\etc 路徑下面的hosts文件,有些電腦是能夠直接修改的,若是不能夠就複製到桌面修改了再放進去這個文件夾下面便可。配置以下:api

127.0.0.1   myWeb.loca/
127.0.0.1   myApi.loca/跨域

個人web主機名:myWeb.loca/(跟配置iis給本身網站取名是同樣的)瀏覽器

個人api主機名:myApi.loca/(跟配置iis給本身網站取名是同樣的)服務器

瀏覽器訪問的時候在前面記得加上:http://myWeb.loca/mvc

 

開啓api路程

接下來我開始實施工程了。上面一系列的配置已經準備好。cors

首先我就要修改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的回調函數裏面沒有執行返回結果。

第一種解決方案

一、咱們先來一個低成本(低版本)的解決方案。由於此版本只須要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/

相關文章
相關標籤/搜索