Visual Studio 2015 Owin+MVC+WebAPI+ODataV4+EntityFrawork+Identity+Oauth2.0+AngularJS 1.x 学习笔记
2016年,.net 会有很多大更新 ASP.NET 5
在此之前我都是用着古老的.net做开发的 (WebForm + IIS)
为了接下来应对 .net 的新功能,我特地去学习了一下基本的 MVC Owin 等等.
接下来我会针对主题写一些学习笔记.
Setup startup Owin + MVC + WebApi
1.New empty project and add folders and code references for "MVC, WebApi".
注: Empty project 就是什么sample都不要有的, add folders and code references 就是要包括 dll , 这里的 MVC 和 WebApi 都是没有包含Owin概念的,我们需要之后自己加入哦。
2.Install "Microsoft.Owin.Host.SystemWeb" (This is for host in IIS)
3.Install "Microsoft.AspNet.WebApi.Owin" (WebApi for OWIN)
3.Add a Startup.cs file with below code
using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using Microsoft.Owin; using Owin; [assembly: OwinStartupAttribute(typeof(Project.Startup))] namespace Project { public partial class Startup { public void Configuration(IAppBuilder app) { //MVC AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); //WebApi var httpConfig = new HttpConfiguration(); WebApiConfig.Register(httpConfig); app.UseWebApi(httpConfig); } } }
4.Remove Global.asax
Startup.cs 就是for Owin 的,我们不再使用 IIS 的 Global.asax 了.
Sample MVC (Model, View and Controller)
微软有一些folders的的结构,我们可以参考 follow
Model,View,Controller 各一个folder
View/Shared 放一些sharing的view
View/Shared/_Layout.cshtml 布局
View/_ViewStart.cshtml 每一个view的初始化
Example for _ViewStart.cshtml
@{ Layout = "~/Views/Shared/_Layout.cshtml"; //每一个View 都是用 _Layout.cshtml 布局, 这个是可以被overwrite掉了. }
Example for _Layout.cshtml
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>@ViewBag.Title</title> <link href="~/Content/bootstrap.min.css" rel="stylesheet" /> @*可以直接用 "~/"*@ @RenderSection("css", required: false) @*RenderSection 可以在子 View 填入内容*@ </head> <body> @RenderBody() @*这个个子 View 内容*@ <script src="~/Scripts/jquery-1.10.2.min.js"></script> @RenderSection("script", required: false) </body> </html>
Controller, Model 与 View 之间的沟通
Example Controller
using System.Collections.Generic; using System; using System.Web.Mvc; using Project.Models; using System.Threading.Tasks; namespace Project.Controllers { [RoutePrefix("")] public class HomeController : AsyncController //Async 可以for EF await { [Route("", Name = "Home")] public async Task<ActionResult> Index(string param) { ViewData["attr"] = "value"; //passing value by 字典 ViewBag.attr = "value"; // passing value by dynamic ViewBag.listStr = new List<string> { "a", "b", "c" }; HomeViewModels homeVM = new HomeViewModels //passing value by ViewModel { content = "strContent", headerViewModels = new HeaderViewModels { content = "headerContent" } }; return View(homeVM); } } }
Example Model
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Project.Models { public class HomeViewModels { public string content { get; set; } public HeaderViewModels headerViewModels { get; set; } } public class HeaderViewModels { public string content { get; set; } } }
如果多的话,可以一个ViewModels 一个 file
Example View
@*初始化*@ @{ ViewBag.title = "Home"; Layout = "~/Views/Shared/_Layout.cshtml"; } @*setup _Layout.cshtml 的 RenderSection*@ @section css { <link href="~/Content/Site.css" rel="stylesheet" /> } @section script { <script src="~/Scripts/jquery.validate.js"></script> } @*setup ViewModels*@ @model Project.Models.HomeViewModels <div> <p>Home</p> @*渲染一个 partial view*@ @Html.Partial("~/Views/Shared/PartialView/header.cshtml", @Model.headerViewModels); <br /> <p>passing value by 字典 : @ViewData["attr"]</p> <p>passing value by dynamic : @ViewBag.attr</p> @*looping*@ @foreach (string str in ViewBag.listStr) { <p>@str</p> } @for (int i = 0; i < ViewBag.listStr.Count; i++) { <p>@i</p> } @*create Link*@ <a href="@Url.RouteUrl("Home",new { param = "param" })">Home</a> <br /> @Html.ActionLink("Home", "Index", "Home", new { param = "param" }, null) </div>
题外话 :
关于 App_Code
以前我是用 website 而不是 project 来开发的,这2者对 App_Code 有点区别
在 project App_Code 创建好 .cs 文件之后,要把属性 -> Build Action 设置成 Compile
关于 SSL
设置成 SSL, 去project 的属性 -> SSL Enabled = true, 然后 right click -> 属性 -> Web -> 把 project url 换成 SSL 的路径
WebApi + AngularJS
如果要使用 OData filter 的话,应该是要装 Microsoft.AspNet.WebApi.OData
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; namespace Project.WebApiControllers { [RoutePrefix("api/products")] public class ProductsController : ApiController { [Route("")] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } } }
@{ Layout = null; } <!DOCTYPE html> <html ng-app="app" ng-controller="ctrl"> <head> <meta name="viewport" content="width=device-width" /> <title>Products</title> </head> <body> <script src="~/Scripts/jquery-2.2.0.min.js"></script> <script src="~/Scripts/angular.min.js"></script> <script> var app = angular.module("app", []); app.controller("ctrl", function ($http) { $http({ url: "https://localhost:44300/api/products", method: "GET" }).then(function (response) { console.log(response); }); }); </script> </body> </html>
WebApi + OData v4
Install "Microsoft.AspNet.OData"
change WebApiConfig to
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Web.OData.Batch; using System.Web.OData.Builder; using System.Web.OData.Extensions; using Microsoft.OData.Edm; using Project.Entity; namespace Project { public static class WebApiConfig { private static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.Namespace = "Project"; builder.ContainerName = "ProjectContainer"; //每一个Entity都要注册到EDM //注意 : 下面这个 "products" 是url prefix, e.g. api/products... 而且OData url 是区分大小写的哦 builder.EntitySet<Product>("products"); return builder.GetEdmModel(); } public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); //config.Routes.MapHttpRoute( // name: "DefaultApi", // routeTemplate: "api/{controller}/{id}", // defaults: new { id = RouteParameter.Optional } //); //"api" 是 url prefix config.MapODataServiceRoute("OData", "api", GetEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer)); config.EnsureInitialized(); } } }
change WebApiController to
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.OData; using System.Web.OData.Routing; using Project.Entity; namespace Project.WebApiControllers { [ODataRoutePrefix("products")] //这个"products"要对应注册EDM的值哦 , e.g. builder.EntitySet<Product>("products") public class ProductsController : ODataController { [ODataRoute("")] public IHttpActionResult Get() { return Ok(new List<Product> { new Product { id = 1, code = "code" } }); } } }
Web.config 要放 ExtensionlessUrlHandler 主要是为了处理 url 的 "."
这里我用的和微软官网有点不同,因为微软的放了,static file 会出现500 error
refer : http://blogs.msdn.com/b/davidhardin/archive/2015/01/13/odata-action-gets-404-due-to-periods-in-url.aspx
<configuration> <system.webServer> <handlers> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <remove name="OPTIONSVerbHandler" /> <remove name="TRACEVerbHandler" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="/api/*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> </handlers> </system.webServer> </configuration>
Install EntityFramework
在 WebConfig 加入
<configuration> <connectionStrings> <add name="DefaultConnection" connectionString="data source=192.168.1.95;Network Library=DBMSSOCN;initial catalog=HotelPlatform;persist security info=True;user id=keatkeat;password=001001;multipleactiveresultsets=True;application name=EntityFramework" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
data source = IP
catalog= Database Name
password = 需要encode for xml
删除掉
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="mssqllocaldb" /> </parameters> </defaultConnectionFactory>
identity + oauth 2.0 待续
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析