1.IOC(轉:https://www.cnblogs.com/artech/p/inside-asp-net-core.html)
IoC的全名Inverse of Control,翻譯成中文就是“控制反轉”或者“控制倒置”。控制反轉也好,控制倒置也罷,它體現的意思是控制權的轉移,即原來控制權在A手中,現在需要B來接管。那么具體對於軟件設計來說,IoC所謂的控制權的轉移具有怎樣的體現呢?要回答這個問題,就需要先了解IoC的C(Control)究竟指的是怎樣一種控制。對於我們所在的任何一件事,不論其大小,其實可以分解成相應的步驟,所以任何一件事都有其固有的流程,IoC涉及的所謂控制可以理解為“針對流程的控制
我們通過一個具體事例來說明傳統的設計在采用了IoC之后針對流程的控制是如何實現反轉的。比如說現在設計一個針對Web的MVC類庫,我們不妨將其命名為MvcLib。簡單起見,這個類庫中只包含如下這個同名的靜態類
public static class MvcLib { public static Task ListenAsync(Uri address); public static Task<Request> ReceiveAsync(); public static Task<Controller> CreateControllerAsync(Request request); public static Task<View> ExecuteControllerAsync(Controller controller); public static Task RenderViewAsync(View view); }
MvcLib提供了如上5個方法幫助我們完成整個HTTP請求流程中的5個核心任務。具體來說,ListenAsync方法啟動一個監聽器並將其綁定到指定的地址進行HTTP請求的監聽,抵達的請求通過ReceiveAsync方法進行接收,我們將接收到的請求通過一個Request對象來表示。CreateControllerAsync方法根據接收到的請求解析並激活請求的目標Controller對象。ExecuteControllerAsync方法執行激活的Controller並返回一個表示視圖的View對象。RenderViewAsync最終將View對象轉換成HTML並作為當前請求響應的內容返回給請求的客戶端。
現在我們在這個MvcLib的基礎上創建一個真正的MVC應用,那么除了按照MvcLib的規范自定義具體的Controller和View之外,我們還需要自行控制從請求的監聽與接收、Controller的激活與執行以及View的最終呈現在內的整個流程,這樣一個執行流程反映在如下所示的代碼中。
class Program { static async Task Main() { while (true) { Uri address = new Uri("http://0.0.0.0:8080/mvcapp"); await MvcLib.ListenAsync(address); while (true) { var request = await MvcLib.ReceiveAsync(); var controller = await MvcLib.CreateControllerAsync(request); var view = await MvcLib.ExecuteControllerAsync(controller); await MvcLib.RenderViewAsync(view); } } } }
2.好萊塢法則
在好萊塢,把簡歷遞交給演藝公司后就只有回家等待。由演藝公司對整個娛樂項目的完全控制,演員只能被動式的接受電影公司的工作,在需要的環節中,完成自己的演出。“不要給我們打電話,我們會給你打電話(don‘t call us, we‘ll call you)”這是著名的好萊塢法則( Hollywood Principle或者 Hollywood Low),IoC完美地體現了這一法則。
在IoC的應用語境中,框架就像是掌握整個電影制片流程的電影公司,由於它是整個工作流程的實際控制者,所以只有它知道哪個環節需要哪些組件。應用程序就像是演員,它只需要按照框架定制的規則注冊這些組件就可以了,因為框架會在適當的時機字典加載並執行注冊的組件。
以熟悉的ASP.NET Core MVC或者ASP.NET MVC應用開發來說,我們只需要按照約定規則(比如目錄結構和命名等)定義相應的Controller類型和View文件就可以了。當ASP.NET (Core )MVC框架在進行處理請求的過程中,它會根據解析生成的路由參數定義為對應的Controller類型,並按照預定義的規則找到我們定義的Controller,然后自動創建並執行它。如果定義在當前Action方法需要呈現一個View,框架自身會根據預定義的目錄約定找到我們定義的View文件,並對它實施動態編譯和執行。整個流程處處體現了“框架Call應用”的好萊塢法則。
總的來說,我們在一個框架的基礎上進行應用開發,就相當於在一條調試好的流水線上生成某種商品,我們只需要在相應的環節准備對應的原材料,最終下線的就是我們希望得到的最終產品。IoC幾乎是所有框架均具有的一個固有屬性,從這個意義上講,“IoC框架”的說法其實是錯誤的,世界上並沒有什么IoC框架,或者說幾乎所有的框架都是IoC框架。
3.依賴注入(DI容器)
IoC主要體現了這樣一種設計思想:通過將一組通用流程的控制權從應用轉移到框架中以實現對流程的復用,並按照“好萊塢法則”實現應用程序的代碼與框架之間的交互。我們可以采用若干設計模式以不同的方式實現IoC
DI是一種“對象提供型”的設計模式,在這里我們將提供的對象統稱為“服務”、“服務對象”或者“服務實例”。在一個采用DI的應用中,在定義某個服務類型的時候,我們直接將依賴的服務采用相應的方式注入進來。按照“面向接口編程”的原則,被注入的最好是依賴服務的接口而非實現。
在應用啟動的時候,我們會對所需的服務進行全局注冊。服務一般都是針對接口進行注冊的,服務注冊信息的核心目的是為了在后續消費過程中能夠根據接口創建或者提供對應的服務實例。按照“好萊塢法則”,應用只需要定義好所需的服務,服務實例的激活和調用則完全交給框架來完成,而框架則會采用一個獨立的“容器(Container)”來提供所需的每一個服務實例。
我們將這個被框架用來提供服務的容器稱為“DI容器”,也由很多人將其稱為“IoC容器”,根據我們在《控制反轉》針對IoC的介紹,我不認為后者是一個合理的稱謂。DI容器之所以能夠按照我們希望的方式來提供所需的服務是因為該容器是根據服務注冊信息來創建的,服務注冊了包含提供所需服務實例的所有信息。
以Autofac框架為列
框架特性
1,靈活的組件實例化:Autofac支持自動裝配,給定的組件類型Autofac自動選擇使用構造函數注入或者屬性注入,Autofac還可以基於lambda表達式創建實例,這使得容器非常靈活,很容易和其他的組件集成。
2,資源管理的可視性:基於依賴注入容器構建的應用程序的動態性,意味着什么時候應該處理那些資源有點困難。Autofac通過容器來跟蹤組件的資源管理。對於不需要清理的對象,例如Console.Out,我們調用ExternallyOwned()方法告訴容器不用清理。細粒度的組件生命周期管理:應用程序中通常可以存在一個應用程序范圍的容器實例,在應用程序中還存在大量的一個請求的范圍的對象,例如一個HTTP請求,一個IIS工作者線程或者用戶的會話結束時結束。通過嵌套的容器實例和對象的作用域使得資源的可視化。
3,Autofac的設計上非常務實,這方面更多是為我們這些容器的使用者考慮:
●組件侵入性為零:組件不需要去引用Autofac。
●靈活的模塊化系統:通過模塊化組織你的程序,應用程序不用糾纏於復雜的XML配置系統或者是配置參數。
●自動裝配:可以是用lambda表達式注冊你的組件,autofac會根據需要選擇構造函數或者屬性注入
●XML配置文件的支持:XML配置文件過度使用時很丑陋,但是在發布的時候通常非常有用
(1).屬性注入
builder.Register(c => new A { B = c.Resolve<B>() });
為了支持循環依賴,使用激活的事件處理程序:
builder.Register(c => new A()).OnActivated(e => e.Instance.B = e.Context.Resolve<B>());
如果是一個反射組件,使用PropertiesAutowired()修改注冊屬性:
builder.RegisterType<A>().PropertiesAutowired();
如果你有一個特定的屬性和值需要連接,你可以使用WithProperty()修改:
builder.RegisterType<A>().WithProperty("PropertyName", propertyValue);
(2).方法注入
調用一個方法來設置一個組件的值的最簡單的方法是,使用一個lambda表達式組件和正確的調用激活處理方法。
builder.Register(c => { var result = new MyObjectType(); var dep = c.Resolve<TheDependency>(); result.SetTheDependency(dep); return result; });
如果你不能使用一個lambda表達式注冊,你可以添加一個激活事件處理程序(activating event handler)
builder .Register<MyObjectType>() .OnActivating(e => { var dep = e.Context.Resolve<TheDependency>(); e.Instance.SetTheDependency(dep); });
(3).構造函數注入
// 創建你的builder var builder = new ContainerBuilder(); // 通常你只關心這個接口的一個實現 builder.RegisterType<SomeType>().As<IService>(); // 當然,如果你想要全部的服務(不常用),可以這么寫: builder.RegisterType<SomeType>().AsSelf().As<IService>();
生命周期
AutoFac中的生命周期概念非常重要,AutoFac也提供了強大的生命周期管理的能力。
AutoFac定義了三種生命周期:
Per Dependency Single Instance Per Lifetime Scope
Per Dependency為默認的生命周期,也被稱為’transient’或’factory’,其實就是每次請求都創建一個新的對象
[Fact] public void per_dependency() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().InstancePerDependency(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); Assert.NotEqual(myClass1,myClass2); }
Single Instance也很好理解,就是每次都用同一個對象
[Fact] public void single_instance() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().SingleInstance(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); Assert.Equal(myClass1,myClass2); }
Per Lifetime Scope,同一個Lifetime生成的對象是同一個實例
[Fact] public void per_lifetime_scope() { var builder = new ContainerBuilder(); builder.RegisterType<MyClass>().InstancePerLifetimeScope(); IContainer container = builder.Build(); var myClass1 = container.Resolve<MyClass>(); var myClass2 = container.Resolve<MyClass>(); ILifetimeScope inner = container.BeginLifetimeScope(); var myClass3 = inner.Resolve<MyClass>(); var myClass4 = inner.Resolve<MyClass>(); Assert.Equal(myClass1,myClass2); Assert.NotEqual(myClass2,myClass3); Assert.Equal(myClass3,myClass4); }
[Fact] public void life_time_and_dispose() { var builder = new ContainerBuilder(); builder.RegisterType<Disposable>(); using (IContainer container = builder.Build()) { var outInstance = container.Resolve<Disposable>(new NamedParameter("name", "out")); using(var inner = container.BeginLifetimeScope()) { var inInstance = container.Resolve<Disposable>(new NamedParameter("name", "in")); }//inInstance dispose here }//out dispose here }
4.過濾器(轉:https://www.cnblogs.com/niklai/p/5676632.html)
下圖展示了Asp.Net Core MVC框架默認實現的過濾器的執行順序:
Authorization Filters:身份驗證過濾器,處在整個過濾器通道的最頂層。對應的類型為: AuthorizeAttribute.cs 對應的接口有同步和異步兩個版本: IAuthorizationFilter.cs 、 IAsyncAuthorizationFilter.cs
Resource Filters:資源過濾器。因為所有的請求和響應都將經過這個過濾器,所以在這一層可以實現類似緩存的功能。對應的接口有同步和異步兩個版本: IResourceFilter.cs 、 IAsyncResourceFilter.cs
Action Filters:方法過濾器。在控制器的Action方法執行之前和之后被調用,一個很常用的過濾器。對應的接口有同步和異步兩個版本: IActionFilter.cs 、 IAsyncActionFilter.cs
Exception Filters:異常過濾器。當Action方法執行過程中出現了未處理的異常,將會進入這個過濾器進行統一處理,也是一個很常用的過濾器。對應的接口有同步和異步兩個版本: IExceptionFilter.cs 、 IAsyncExceptionFilter.cs
Result Filters:返回值過濾器。當Action方法執行完成的結果在組裝或者序列化前后被調用。對應的接口有同步和異步兩個版本: IResultFilter.cs 、 IAsyncResultFilter.cs
5.中間件(轉https://www.cnblogs.com/niklai/p/5665272.html)
Asp.Net Core,管道模型流程圖
IHttpModule和IHttpHandler不復存在,取而代之的是一個個中間件(Middleware)。
Server將接收到的請求直接向后傳遞,依次經過每一個中間件進行處理,然后由最后一個中間件處理並生成響應內容后回傳,再反向依次經過每個中間件,直到由Server發送出去。
中間件就像一層一層的“濾網”,過濾所有的請求和相應。這一設計非常適用於“請求-響應”這樣的場景——消息從管道頭流入最后反向流出。
接下來將演示在Asp.Net Core里如何實現中間件功能。
IHttpModule和IHttpHandler不復存在,取而代之的是一個個中間件(Middleware)。
Server將接收到的請求直接向后傳遞,依次經過每一個中間件進行處理,然后由最后一個中間件處理並生成響應內容后回傳,再反向依次經過每個中間件,直到由Server發送出去。
中間件就像一層一層的“濾網”,過濾所有的請求和相應。這一設計非常適用於“請求-響應”這樣的場景——消息從管道頭流入最后反向流出。
接下來將演示在Asp.Net Core里如何實現中間件功能。
Middleware
Middleware支持Run、Use和Map三種方法進行注冊,下面將展示每一種方法的使用方式。
Run方法
所有需要實現的自定義管道都要在 Startup.cs 的 Configure 方法里添加注冊。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.Run(async context => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中間件 //app.UseMvc(); }
啟動調試,訪問地址 http://localhost:5000/ ,頁面顯示Hello World!字樣
再次添加一個Run方法
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.Run(async context => { await context.Response.WriteAsync("Hello World!"); }); app.Run(async context => { await context.Response.WriteAsync("Hello World too!"); }); // 添加MVC中間件 //app.UseMvc(); }
啟動調試,再次訪問發現頁面上只有Hello World!字樣。
原因是:Run的這種用法表示注冊的此中間件為管道內的最后一個中間件,由它處理完請求后直接返回。
Use方法
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中間件 //app.UseMvc(); }
啟動調試,訪問頁面同樣顯示Hello World!字樣。我們發現使用Use方法替代Run方法,一樣可以實現同樣的功能。
再次添加一個Use方法,將原來的Use方法內容稍作調整,嘗試實現頁面顯示兩個Hello World!字樣。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); await next(); }); app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World too!"); }); // 添加MVC中間件 //app.UseMvc(); }
將兩個Use方法換個順序,稍微調整一下內容,再次啟動調試,訪問頁面,發現字樣輸出順序也發生了變化。
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); HelloworldMiddleware.cs // 添加自定義中間件 app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World too!"); await next(); }); app.Use(async (context, next) => { await context.Response.WriteAsync("Hello World!"); }); // 添加MVC中間件 //app.UseMvc(); }
從上面的例子可以發現,通過Use方法注冊的中間件,如果不調用next方法,效果等同於Run方法。當調用next方法后,此中間件處理完后將請求傳遞下去,由后續的中間件繼續處理。
當注冊中間件順序不一樣時,處理的順序也不一樣,這一點很重要,當注冊的自定義中間件數量較多時,需要考慮哪些中間件先處理請求,哪些中間件后處理請求。
另外,我們可以將中間件單獨寫成獨立的類,通過UseMiddleware方法同樣可以完成注冊。下面將通過獨立的中間件類重寫上面的演示功能。
新建兩個中間件類: HelloworldMiddleware.cs 、 HelloworldTooMiddleware.cs
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace WebApiFrame.Core.Middlewares { public class HelloworldMiddleware { private readonly RequestDelegate _next; public HelloworldMiddleware(RequestDelegate next){ _next = next; } public async Task Invoke(HttpContext context){ await context.Response.WriteAsync("Hello World!"); await _next(context); } } } HelloworldMiddleware.cs
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace WebApiFrame.Core.Middlewares { public class HelloworldTooMiddleware { private readonly RequestDelegate _next; public HelloworldTooMiddleware(RequestDelegate next){ _next = next; } public async Task Invoke(HttpContext context){ await context.Response.WriteAsync("Hello World too!"); } } } HelloworldTooMiddleware.cs
修改 Startup.cs 的Configure方法內容
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.UseMiddleware<HelloworldMiddleware>(); app.UseMiddleware<HelloworldTooMiddleware>(); // 添加MVC中間件 //app.UseMvc(); }
啟動調試,訪問頁面,可以看到同樣的效果。
Map方法
Map方法主要通過請求路徑和其他自定義條件過濾來指定注冊的中間件,看起來更像一個路由。
修改 Startup.cs 的Configure方法內容,增加靜態方法MapTest
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.Map("/test", MapTest); // 添加MVC中間件 //app.UseMvc(); } private static void MapTest(IApplicationBuilder app){ app.Run(async context => { await context.Response.WriteAsync("Url is " + context.Request.PathBase.ToString()); }); }
啟動調試,訪問路徑 http://localhost:5000/test ,頁面顯示如下內容
但是訪問其他路徑時,頁面沒有內容顯示。從這個可以看到,Map方法通過類似路由的機制,將特定的Url地址請求引導到固定的方法里,由特定的中間件處理。
另外,Map方法還可以實現多級Url“路由”,其實就是Map方法的嵌套使用
// 添加自定義中間件 app.Map("/level1", lv1App => { app.Map("/level1.1", lv11App => { // /level1/level1.1 }); app.Map("/level1.2", lv12App => { // /level1/level1.2 }); });
也可以通過MapWhen方法使用自定義條件進行“路由”
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { // 添加日志支持 loggerFactory.AddConsole(); loggerFactory.AddDebug(); // 添加NLog日志支持 loggerFactory.AddNLog(); // 添加自定義中間件 app.MapWhen(context => { return context.Request.Query.ContainsKey("a"); }, MapTest); // 添加MVC中間件 //app.UseMvc(); } private static void MapTest(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync($"Url is {context.Request.Path.ToString()}{context.Request.QueryString.Value}"); }); }
啟動調試,訪問路徑 http://localhost:5000/path?a=1&b=2 ,頁面顯示如下內容
只有當請求參數中含有a時,頁面才正常顯示內容。
其他內置的中間件
Asp.Net Core框架內置了幾個中間件
6.路由(轉https://www.cnblogs.com/tianma3798/p/6920638.html)
1.API定義
/* * API 定義如下 * GET api/menu 獲取菜單列表 * POST api/menu 添加模塊 * PUT api/menu 修改模塊 * PATCH api/menu 修改菜單信息 * DELETE api/menu 刪除模塊 */
2.后台代碼 :
MenuModelContext _Context = new MenuModelContext(); /// <summary> /// 獲取列表 /// </summary> /// <returns></returns> [HttpGet] public IEnumerable<Menu> Get() { List<Menu> list = _Context.Menu.ToList(); return list; } /// <summary> /// 添加模塊對象 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPost] public bool Add(Model m) { try { m.AddTime = DateTime.Now; _Context.Model.Add(m); _Context.SaveChanges(); return true; } catch (Exception ex) { return false; } } /// <summary> /// 修改模塊 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPut] public bool Update(Model m) { try { Model oldModel = _Context.Model.Find(m.ModelId); oldModel.ModelName = m.ModelName; oldModel.SortNumber = m.SortNumber; _Context.SaveChanges(); return true; } catch (Exception ex) { return false; } } /// <summary> /// 修改菜單對象 /// </summary> /// <param name="m"></param> /// <returns></returns> [HttpPatch] public IActionResult Update(Menu m) { try { Menu oldMenu = _Context.Menu.Find(m.MenuId); if (oldMenu == null) return NotFound("你要訪問的菜單不存在或已經刪除"); oldMenu.MenuName = m.MenuName; oldMenu.SortNumber = m.SortNumber; oldMenu.ModelId = m.ModelId; _Context.SaveChanges(); return Ok(); } catch (Exception ex) { return Content(ex.Message); } } /// <summary> /// 刪除模塊 /// </summary> /// <param name="ids"></param> /// <returns></returns> [HttpDelete] public IActionResult Delete(string ids) { try { if (string.IsNullOrEmpty(ids)) throw new Exception("獲取id參數失敗"); List<int> idList = ids.Split(',').Select(q => Convert.ToInt32(q)).ToList(); List<Model> list = _Context.Model.Where(q => idList.Contains(q.ModelId)).ToList(); _Context.Model.RemoveRange(list); int count = _Context.SaveChanges(); //使用OkObjectResult 前台jquery自動解析為object對象,不需要進行反序列化處理 //返回的不是字符串 return Ok(new { msg = $"刪除成功,總共刪除{count}條數據" }); } catch (Exception ex) { //使用ContentResult返回字符串處理 return Content(ex.Message); } }
3.jQuery ajax代碼
//Get獲取列表數據 function testOne() { $.get(urlHelper.getApi('menu'), {}, function (data) { console.info(data); var menu1 = new Vue({ el: '#menu1', data: { result: data } }); }) } testOne(); //添加菜單 var example2 = new Vue({ el: '#example-2', data: { name:'添加菜單' }, //在 methods 對象中定義方法 methods: { addMenu: function (event) { //使用 Post提交添加菜單 var _this = this; this.name = '正在提交...'; $.post(urlHelper.getApi('menu'), { ModelName: '測試菜單5', SortNumber:5 }, function (data) { console.info(data); _this.name = '提交成功'; }); }, updateModel: function (event) { //使用put提交修改模塊 var _this = this; $.ajax({ url: urlHelper.getApi('menu'), type: 'put', data: { ModelId: '4', ModelName: '模塊abc', SortNumber: 4 }, success: function (data) { console.info(data); if (data == true) alert('修改成功'); else alert('修改失敗'); } }); } } }); //修改菜單、刪除模塊 var btngroup1 = new Vue({ el: '#btngroup1', data: { name: '修改菜單', name1: '刪除模塊' }, methods: { updateMenu: function (e) { var _this = this; //使用patch 方式修改菜單 $.ajax({ url: urlHelper.getApi('menu'), type:'patch', data: { MenuID: 1, MenuName: '測試菜單One', SortNumber: 100, ModelID:2 }, success: function (data) { console.info(data); } }); }, deleteMenu: function (e) { //使用delete 提交方式刪除模塊 $.ajax({ url: urlHelper.getApi('menu'), type: 'delete', data: { ids:[1003] }, success: function (data) { console.info(data); }, error: function (data) { console.info(data); } }); } } });
根據HttpMethod的Template路由示例
1.API定義
/* * API 定義 * GET api/menu/{id} 獲取指定ID的菜單對象 * GET api/menu/getmodel 獲取模塊列表內容 */
[HttpGet("{id}")] public IActionResult Get(int ID) { Menu m = _Context.Menu.Find(ID); if (m == null) return NotFound(); return Json(m); } //特別說明:路由中的Template的值不可以包含斜杠/ [HttpGet("getmodel")] public IActionResult GetModel() { List<Model> list = _Context.Model.ToList(); return Json(list); }
Jquery 的ajax代碼
//其他Get方式測試 var btngroup2 = new Vue({ el: '#btngroup2', data: { name: '獲取菜單對象', name1: '獲取模塊列表', item: {} //Vue的對象綁定,沒有的情況下需要一個空對象,不然報錯 }, methods: { getMenu: function (e) { var _this = this; //鏈接地址格式 :http://localhost:50000/api/menu/1/ $.get(urlHelper.getApi('menu','1'), { }, function (data) { console.info(data); _this.item = data; }); }, getModel: function (e) { var _this = this; $.get(urlHelper.getApi('menu', 'getmodel'), {}, function (data) { console.info(data); }) } } });
7.Startup
/// <summary> /// 此方法由運行時調用。使用此方法向容器添加服務。 /// </summary> /// <param name="services">For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940</param> /// <returns>DI容器</returns> public IServiceProvider ConfigureServices(IServiceCollection services) { //添加MVC services.AddMvc( // 配置異常過濾器 config => { config.Filters.Add(typeof(CustomExceptionFilter)); } ) // 設置json序列化方式 .AddJsonOptions(mvcJsonOptions => { //忽略循環引用 mvcJsonOptions.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //不使用駝峰樣式的key mvcJsonOptions.SerializerSettings.ContractResolver = new DefaultContractResolver(); //設置時間格式 mvcJsonOptions.SerializerSettings.DateFormatString = Const.yyyyMMddHHmmss; }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddCors(options => { options.AddPolicy("AllowSpecificOrigins", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); }); // 注冊服務並且實例化AutoFac替換默認容器 var containerBuilder = new ContainerBuilder(); //實例化 AutoFac 容器 // 注冊用戶服務 containerBuilder.RegisterType<UserService>().As<IUserService>(); containerBuilder.Populate(services); ApplicationContainer = containerBuilder.Build(); return new AutofacServiceProvider(ApplicationContainer); //第三方IOC接管 core內置DI容器 }
/// <summary> /// 此方法由運行時調用。使用此方法配置HTTP請求管道。 /// </summary> /// <param name="app">app</param> /// <param name="env">env</param> public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //if (env.IsDevelopment()) //{ // app.UseDeveloperExceptionPage(); //} //app.UseExceptionHandler( // options => { // options.Run( // async context => // { // context.Response.StatusCode = (int)HttpStatusCode.OK; // context.Response.ContentType = "text/html"; // var ex = context.Features.Get<IExceptionHandlerFeature>(); // if (ex != null) // { // var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace }"; // await context.Response.WriteAsync(err).ConfigureAwait(false); // } // }); // } //); //啟動跨域 app.UseCors("AllowSpecificOrigins"); //注入MVC路由 app.UseMvc(); }