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 待续 

 

posted @ 2016-01-21 11:44  兴杰  阅读(828)  评论(0编辑  收藏  举报