Self-host WebApi với Owin middleware
Trong bài viết trước tôi đã giới thiệu tới các bạn những khái niệm cơ bản về OWin (Open Web Interface for Net), các bạn có thể xem lại theo link sau: Tổng quan về Owin - Open Web Server Interface for .NET Để tiếp tục làm quen với Owin, trong bài viết này chúng ta sẽ xây dựng một Owin middleware ...
Trong bài viết trước tôi đã giới thiệu tới các bạn những khái niệm cơ bản về OWin (Open Web Interface for Net), các bạn có thể xem lại theo link sau:
Tổng quan về Owin - Open Web Server Interface for .NET
Để tiếp tục làm quen với Owin, trong bài viết này chúng ta sẽ xây dựng một Owin middleware đơn giản cho web api.
Trước khi đi vào triển khai ứng dụng, chúng ta cần biết về Katana. Vậy Katana là gì? Đây là một project open source giúp cho việc xây dựng và hosting OWIN-based web applications, nó được phát triển bởi Microsoft.
Bước tiếp theo chúng ta sẽ từng bước xây dựng middleware với Owin và Katana.
1. SimpleMiddleware class
Đây là tên class của middleware, đơn là chỉ là một tên mà tôi đặt, nó được kế thừa OwinMiddleware class (một built-in của Owin library):
public class SimpleMiddleware: OwinMiddleware { public SimpleMiddleware(OwinMiddleware next) : base(next) { } public async override Task Invoke(IOwinContext context) { context.Response.Headers["MachineName"] = Environment.MachineName; await Next.Invoke(context); } }
2. Startup class
Tại đây chúng ta thực hiện cấu hình việc sử dụng route cho Asp.net API, custom middleware, file option server,..
public class Startup { // This method is required by Katana: public void Configuration(IAppBuilder app) { // Adding to the pipeline with our own middleware app.Use(async (context, next) => { // Add Header context.Response.Headers["Product"] = "Web Api and Owin Middleware"; // Call next middleware await next.Invoke(); }); // Custom Middleare app.Use(typeof(SimpleMiddleware)); // Configure Web API for self-host. var config = ConfigureWebApi(); // Web Api app.UseWebApi(config); // File Server var options = new FileServerOptions { EnableDirectoryBrowsing = true, EnableDefaultFiles = true, DefaultFilesOptions = { DefaultFileNames = { "home.html" } }, FileSystem = new PhysicalFileSystem("StaticFiles"), StaticFileOptions = { ContentTypeProvider = new FileExtensionContentTypeProvider() } }; app.UseFileServer(options); } private HttpConfiguration ConfigureWebApi() { var config = new HttpConfiguration(); config.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }); return config; } } }
Trong đó, phần cấu hình FileServerOptions giúp middleware có thể duyệt những static files, kết quả tôi sẽ được trình bày ở phần sau.
3. Program class
Tại hàm main của chương trình tôi dùng đối tượng HostFactory để thực hiện chạy server, đây là một class nằm trong thư viện Topshelf. Đây là một framework hỗ trợ việc hosting service được viết trong .Net. Các bạn có thể tìm hiểu sau hơn về nó tại đây. chúng ta tìm và add nó tới project từ Nuget.
static void Main(string[] args) { Console.WriteLine("Starting web Server..."); HostFactory.Run(x => { x.Service<OwinServer>(s => { s.ConstructUsing(name => new OwinServer()); s.WhenStarted(tc => tc.Start()); s.WhenStopped(tc => tc.Stop()); }); x.RunAsLocalSystem(); x.SetDescription("This is application of a Windows Service using Topshelf."); x.SetDisplayName("Self Host Web API and Owin Middleware"); x.SetServiceName("AspNetSelfHostWithMiddleware"); }); Console.WriteLine("Server running at {0} - press Enter to quit. ", "http://localhost:8080"); Console.ReadLine(); }
Các bạn có thể thấy ở đây Topshelf giúp ứng dụng có thể chạy như một service, có thể cấu hình: description, displayName, serviceName. Lưu ý rằng, service được cấu hình để sử dụng OwinServer class
public class OwinServer { private IDisposable _webapp; public void Start() { _webapp = WebApp.Start<Startup>("http://localhost:8080"); } public void Stop() { _webapp.Dispose(); } }
Tại OwinServer class, chúng ta đơn giản thực hiện việc kích hoạt web server khởi chạy và lắng nghe tại cổng 8080 của localhost.
4. Xây dựng model và controller
Chúng ta sẽ xây dựng một api controller để thực hiện hiển thị dữ liệu trên web. Tôi sử dụng một đối tượng Product
public class Product { public int Id { get; set; } public string Name { get; set; } }
Controller:
public class ProductsController : ApiController { private List<Product> _products = new List<Product> { new Product {Id = 1, Name = "Product 1"}, new Product {Id = 2, Name = "Product 1"}, new Product {Id = 3, Name = "Product 1"}, new Product {Id = 4, Name = "Product 1"}, new Product {Id = 5, Name = "Product 1"} }; // api/products/ public IEnumerable<Product> Get() { return _products; } // api/products/id public Product Get(int id) { var product = _products.FirstOrDefault(c => c.Id == id); if (product == null) { throw new HttpResponseException( System.Net.HttpStatusCode.NotFound); } return product; } public async Task<IHttpActionResult> Post(Product product) { return Ok(); } public async Task<IHttpActionResult> Put(Product product) { return Ok(); } public async Task<IHttpActionResult> Delete(int id) { return Ok(); } }
Để đơn giản hóa cho ứng dụng demo, tôi sử dụng một list product có sẵn như trên. Đồng thời, tôi chỉ triển khai hai api: getAll, getOne.
5. Kết quả
Nhấn F5 chạy chương trình, chúng ta có thông tin server như bên dưới:
Tiếp theo, chúng ta gõ trên trình duyệt, thông tin được hiển thị như bên dưới:
Thông tin static file được hiển thị bởi vì chúng ta đã cấu hình file option server tại startup class, nó giúp cho middleware có thể duyệt những file tĩnh trong thư mục. Sau khi click vào link testFile.txt thì nội dung file sẽ được hiển thị:
Để biết các api có làm việc hay không, chúng ta gõ trên trình duyệt các api.
/api/products/
/api/products/id/
Thêm nữa, chúng ta cũng có thể check thêm một số thông tin cấu hình của middleware thông qua header của request, như các bạn thấy bên dưới
Ta có thể hiểu thông tin đó lấy từ đâu, nhìn lại những dòng code dưới đây:
context.Response.Headers["MachineName"] = Environment.MachineName;
context.Response.Headers["Product"] = "Web Api and Owin Middleware";
7. Thảo luận
Với một ứng dựng middleware đơn giản ở trên, hy vọng các bạn có thể hình dung Owin, Katana dùng để làm gì và ứng dụng của nó ở đâu. Chúc các bạn thành công.