.Net MVC我的筆記

前言

寫了一個.Net MVC的我的筆記,可是不是MarkDown,好難受,博客園也不支持之前的舊文章轉MarkDown,之後有時間看看能不能整理一下,此次新開一個MarkDown的html

母版頁節點

在母版頁的footer裏面寫前端

<footer>    
     @RenderSection("Footer")
</footer>

而後在子頁中寫java

@section Footer{
    <h3>你們好,我是腳</h3>
}

這樣就能夠把子頁的內容放到母版頁的節點位置了程序員

Controller將數據傳給View的方式

ViewBag和ViewData共享數據

public ActionResult Index () {
     ViewBag.UserName = "小李飛刀";
     ViewData["UserName"] = "陸小鳳";
     TempData["UserName"] = "楚留香"; //臨時數據

     User model = new User { UserName = "謝曉峯" };

     return View (model); //這行代碼其實就至關於ViewData.Model=model
 }

View代碼web

@{
    ViewBag.Title = "Index";
}

<div>@ViewBag.UserName </div>
<div>@ViewData["UserName"] </div>
<div>@TempData["UserName"] </div>
<div>@Model.UserName</div>

結果是:ajax

陸小鳳數據庫

陸小鳳編程

楚留香json

謝曉峯

緣由是ViewData和ViewBag本質上都是【ViewDataDictionary】類型,而且二者之間的數據共享,只不過提供了不一樣的語法操做方式而已。因此「陸小鳳」覆蓋了原先的值」小李飛刀「。

TempData使用一次以後會當即刪除數據

至於Model,在視圖裏面能夠直接使用@Model.username進行使用,可是你會發現沒有提示,這個是由於編譯器沒法在編譯的時候獲取Model的類型,若是想要提示能夠這樣作,在視圖的上面寫上@model是user類型的,注意必須是@model小寫的,不能是@Model

@model    User

Visual Studio不顯示添加的文件

有的時候我在項目的文件夾里加了一些文件,可是Visual Studio不顯示,明明已經加了,就是不顯示,這時候能夠點擊顯示全部文件按鈕,以下圖

點擊了這個按鈕,全部的文件都會顯示了

Ajax

Ajax在.net MVC中用的很是多,通常是用來從後端獲取數據,而後無刷新加載,Ajax的特色就是無刷新加載

普通的Ajax使用方法

基本上使用Ajax都是使用Jquery的Ajax,因此Jquery的js文件引用一下,最好放在母版頁裏面,這樣全部的子頁直接開寫

獲取文本內容加載

前端,Razor

@{
    ViewBag.Title = "Index";
}

<h2>我是學習ajax的頁面</h2>

<div>
    <p id="text">我是字段</p>
    <button id="ctbtn">傳統ajax</button>
</div>

<script>
    $(function () {
        $('#ctbtn').click(function () {
            $.post('/Ajax/GetData', { id: 666 }, function (data, status) {
                $('#text').html(data + '  狀態是:' + status);
            });
        });
    });
</script>

後端:

public ActionResult GetData(int id) {
            return Json("普通的Ajax"+id,JsonRequestBehavior.AllowGet);
        }

其實前端的ajax有三種,load,get和post,也能夠寫成

<script>
    $(function () {
        $('#ctbtn').click(function () {
            $.get('/Ajax/GetData', { id: 666 }, function (data, status) {
                $('#text').html(data + '  狀態是:' + status);
            });
        });
    });
</script>

獲取Model數組類型加載

新建一個Model,我新建的是User,以下

public class User
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Phone { get; set; }
    }

而後前端Razor如此:

<script>
    $(function () {
        $('#ctbtn').click(function () {
            $.post('/Ajax/GetData', { id: 666 }, function (data, status) {

                $.each(data, function (key, value) {
                    //console.log(data[key].Name); 不須要再使用data了,能夠直接使用value,這個value就是一個User對象,後面的屬性記得保持一致,沒有提醒
                     console.log(value.Name); 
                });

            });
        });
    });
</script>

後端返回一個Json就能夠了

public ActionResult GetData(int id) {

            List<User> userList = new List<User>()
            {
                new User(){ Name="蜀雲泉",Sex="男",Phone=123 },
                new User(){ Name="許嵩",Sex="男",Phone=123 },
                new User(){ Name="林俊杰",Sex="男",Phone=123 }
            };

            return Json( userList );
        }

看看效果圖

非入侵式Ajax(Unobtrusive Ajax)

這個簡單的介紹一下,什麼是非入侵式,就是前端頁面只有純粹的HTML和CSS,HTML元素裏面沒有一丁點的JavaScript,好比onclick方法之類的,全部的JavaScript都是單獨的一個文件,這就是非入侵式,可是,根據我目前的水平來看,根據我目前接觸的項目來看,JavaScript都是寫在Razor裏面的,並無作到非入侵式,因此簡單的介紹一下

打開.Net MVC的web.config文件,你能夠發現以下

<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />

這兩行就是開啓客戶端驗證和非入侵式JavaScript的

若是隻想在指定頁面關閉非入侵式,能夠在頁面寫

@{ Html.EnableUnobtrusiveJavaScript(false); }
@{ Html.EnableClientValidation(false); }

==講真這個非入侵式開啓關閉什麼的,我是沒有看懂的,有什麼用?==

AjaxHelper

這個是封裝的,分爲異步鏈接按鈕和異步表單,知道了就好了,感受用的很少,不學

MVC Areas 區域

爲何會有Areas?由於多人協做,好比一個網站,我作購物車,你作商品管理,他作權限驗證,若是使用普通的都在Controller文件夾裏面新建Controller,在View文件夾裏新建View,你會發現,好亂啊

Areas出現了,我作購物車,使用購物車Areas,你作商品管理,使用商品管理Areas

固然,首先每一個部分都得有必定的複雜度,要是很簡單的幾個Controller就完成的模塊,就不要分Areas了

新建Areas

新建一個AdminAreas,新建完成以後以下

點開AdminAreaRegistration看看,很明顯裏面的路由變成了Controller前面加了Admin

在Admin這個區域裏面的Controller新建index,運行,都是同樣的

不知道發現了沒,看看上圖,除了路由的文件多加了一個Admin,其餘的文件夾很明顯的三層,Controller,Model,View,因此Areas其實就至關於新建了一個文件夾而已,都是在項目內

把Areas轉移到類庫

先說一下,轉移到類庫有什麼好處.首先,仍是我上面說的,具有必定複雜度的模塊纔會新建一個Areas,兩三個Controller就能夠實現的模塊不必新建Areas

那麼問題來了,多人協做的時候,我在Admin的Areas裏面新建東西,寫代碼,測試,我一提交,那麼StudyMVC這個項目的人就得獲取個人代碼,就得編譯,萬一個人AdminAreas有bug,他必須等我修復bug

新建一個類庫就不同了,我StudyMVC引用了你這個類庫,你類庫有問題不影響個人主項目,你編譯你本身的,我編譯我本身的

新建.Net FrameWork類庫

我第一次沒看清,新建的是.Net Standard,坑死了啊,選Net FrameWork類庫

而後把StudyMVC裏面的AdminAreas裏面的AdminAreaRegistration.cs複製到外面類庫AdminAreas裏面,複製以後,會報錯,這是由於必須引用兩個文件

第一個using System.Web.Mvc,使用Nuget引用本地的就行

第二個using System.Web,這個就更簡單了,直接在類庫的引用上面右鍵添加引用就能夠了

AdminAreaRegistration.cs文件複製到類庫以後,原項目裏面的就刪了,原項目StudyMVC右鍵添加服務引用,引用AdminAreas這個類庫

而後再來運行一下,輸入Admin這個區域加上原項目的Controller,發現運行同樣是ok的

若是你沒有運行成功,請再次檢查你的MVC項目有沒有引用區域類庫

==重點來了==

我如今在AdminAreas類庫裏面新建一個文件夾,叫Controller,而後新建一個Controller叫UserController,可能你沒法新建控制器,能夠從StudyMVC項目裏面複製一個控制器過來,改更名字就行了

UserController裏面新建一個Index方法,而後在MVC項目的Admin區域裏面的View裏面新建對應的User文件夾,下面新建Index.cshtml

給大家看看代碼吧

首先外部AdminAreas類庫的UserController

using System.Web.Mvc;

namespace StudyMVC.Areas.Admin.Controllers
{
    public class UserController : Controller
    {
        // GET: Admin/AreaTest
        public ActionResult Index()
        {
            ViewBag.user = "我是區域類庫裏面的UserController";
            return View();
        }
    }
}

而後,我是MVC項目裏面的index.cshtml

@{
    Layout = null;
}

<h2>什麼東西</h2>
<h2>@ViewBag.user</h2>

最後,結果大圖

我講一下,這個區域啊,放到外部的類庫以後,就好多了.個人Admin區域的Controller在類庫裏,隨便過來一個程序員,你改吧,只要符合個人前端cshtml的要求,返回值不要動,其餘的邏輯代碼你隨便改

並且,改完以後,你本身在類庫裏面編譯,編譯成功後把dll丟給個人MVC項目就能夠了

看到這裏,可能有人會有疑問,爲何Controller丟在外面的類庫,視圖cshtml還在MVC 內部呢?

由於Controller是代碼須要編譯.....

視圖cshtml不須要編譯......

並且視圖一旦寫好了,不會常常修改的,反而是後臺,會須要修修改改,因此我只須要定好我這個前端cshtml須要的返回值,你類庫那邊的Controller怎麼寫我不關心,只要返回值給對就行

我終於學會了Areas了

對象加問號判斷是否爲空

代碼以下:

User user = null;
if (user?.Name=="蜀雲泉")
{
    Console.WriteLine("測試");
}

若是我不加?的話,由於user對象是null,因此我調用user.Name的時候會直接報錯

對象後接一個?就是判斷是否爲空的意思,若是是空的話就不會執行判斷了,很好用

過濾器

過濾器通常用來作身份驗證,好比購物電商網站,你在購買的時候會檢測你是否登陸,若是沒登陸就讓你登陸,還有其餘不少地方須要身份驗證的,若是你每一個地方都寫一次身份驗證的代碼,那就違背DRY原則了,代碼重複了

因此,有了過濾器,這個至關於AOC切面編程

三種過濾器

  • ActionFilterAttribute:方法執行以前後和結果執行以前後
  • AuthorizeAttribute:首先執行,在全部方法或過濾器以前
  • HandleErrorAttribute:異常過濾器

我不會詳細介紹,網上大把,我簡單的說一下怎麼用

新建過濾器

通常都是在Filter文件夾下面新建,個人

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace StudyMVC.Filter
{
    /// <summary>
    /// 這是我寫的第一個過濾器,過濾器一般用在身份驗證吧我感受,F12進去看看ActionFilterAttribute就知道了
    /// </summary>
    public class MyCustomerFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write("方法執行以前");
            base.OnActionExecuting(filterContext);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write("方法執行以後");
            base.OnActionExecuted(filterContext);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write("視圖加載以前");
            base.OnResultExecuting(filterContext);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write("視圖加載以後");
            base.OnResultExecuted(filterContext);
        }

    }
}

爲何我會這麼寫?由於你在ActionFilterAttribute上按下F12,查看源代碼就知道了,以下

#region 程序集 System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// 未知的位置
// Decompiled with ICSharpCode.Decompiler 4.0.0.4285
#endregion

namespace System.Web.Mvc
{
    //
    // 摘要:
    //     Represents the base class for filter attributes.
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
    {
        //
        // 摘要:
        //     Called by the ASP.NET MVC framework before the action method executes.
        //
        // 參數:
        //   filterContext:
        //     The filter context.
        public virtual void OnActionExecuting(ActionExecutingContext filterContext)
        {
        }

        //
        // 摘要:
        //     Called by the ASP.NET MVC framework after the action method executes.
        //
        // 參數:
        //   filterContext:
        //     The filter context.
        public virtual void OnActionExecuted(ActionExecutedContext filterContext)
        {
        }

        //
        // 摘要:
        //     Called by the ASP.NET MVC framework before the action result executes.
        //
        // 參數:
        //   filterContext:
        //     The filter context.
        public virtual void OnResultExecuting(ResultExecutingContext filterContext)
        {
        }

        //
        // 摘要:
        //     Called by the ASP.NET MVC framework after the action result executes.
        //
        // 參數:
        //   filterContext:
        //     The filter context.
        public virtual void OnResultExecuted(ResultExecutedContext filterContext)
        {
        }
    }
}

裏面說的很明白了,方法執行先後,和結果執行先後

使用過濾器

由於過濾器是AOC面向切面編程的產物,因此使用很方便,有三種方式,不過最經常使用的仍是在方法上加,其餘兩個一個是在Controller上加,一個是在全局過濾器加,不講。

[MyCustomerFilter]
        public ActionResult Index()
        {
            string test = string.Format("{0:P0}", 0.24583);

            return View(); 
        }

就是這麼簡單,Index這個方法已經加上過濾器了,

緩存

這裏講一下OutputCache這個緩存

我在Index方法上加上OutputCache緩存,以下

[OutputCache(Duration =5)]
        public ActionResult Index()
        {
            ViewBag.time = DateTime.Now.ToString();
            Response.Cache.SetOmitVaryStar(true);
            return View();
        }

Duration這個屬性是時間,就是緩存幾秒的意思,屬性有不少,不寫,去網上查

運行,發現,網絡是200,而後我刷新一次,發現是304,以下圖

這個304就是從緩存讀取的意思,由於我設置了Duration緩存時間爲5秒,因此,你在5秒內刷新都是304,過了5秒就又變成200了

SEO

SEO,搜索引擎優化。作網站最看重的就是SEO了吧,這關乎到你的網站在搜索引擎中的權重,SEO作的好,就會出如今搜索引擎的前幾名,對網站的流量和知名度影響很大

開發時要考慮SEO

蜘蛛只爬取靜態HTML

JavaScript動態生成的HTML,蜘蛛是不會爬取的,蜘蛛就是各大搜索引擎獲取網站信息的工具,說到這裏我想到了一點,Bootstrap Table這個插件是在js裏面生成表格的,這樣蜘蛛就不會爬取,SEO會變差

使用a標籤,不要使用LinkButton

由於搜索引擎蜘蛛只認a標籤,不認JavaScript,例如

<a href="javascript:document.location='www.baidu.com'">百度</a>

這個搜索引擎的蜘蛛是不認的,而LinkButton就是這個

Lucene.Net分詞

WebService

WebService是什麼暫且不細說,先看看怎麼新建最簡單的WebService

新建空的EntityFramework網站

直接右鍵新建空的EntityFramework網站,沒什麼好說的

新建WebService

這個新建Web服務便可,如圖

個人命名是MyWebService,雙擊打開能夠看到裏面已經有了一個HelloWorld方法

如今咱們來新加一個方法,以下:

[WebMethod]
 public int Multiplier(int a,int b)
 {
     return a * b;
 }

直接在MyWebService右鍵,在瀏覽器中運行,如圖


超經典的圖面了,這就是WebService了,你點擊Multiplier,還能夠直接在線測試方法

調用WebService

首先,項目先引用WebService,直接在引用那裏,右鍵添加服務引用,選擇咱們剛纔的WebService地址便可,注意,這裏引用的地址不要和WebService重名了

而後新建一個Razor頁面來測試吧,單純的HTML沒辦法寫C#,仍是Razor好用

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>

        @{
            WebService.ServiceReference.MyWebServiceSoapClient client = new WebService.ServiceReference.MyWebServiceSoapClient();
            <text>@client.Multiplier(5,6)</text>
        }

    </div>
</body>
</html>

直接右鍵運行這個Razor,能夠直接看到30,至此,最簡單的WebService建立和調用完成了

調用網絡上的WebService

這個有點坑啊,本地的WebService是直接添加服務引用,網絡上的不同,須要點擊添加服務引用,點擊高級=>添加Web引用才能夠,以下圖,網絡的WebService帶有Web

咱們這裏以天氣服務助手爲例,網上搜一下天氣服務助手,能夠搜到這個

http://www.webxml.com.cn/WebServices/WeatherWS.asmx

你能夠點着看看各個接口是幹嗎的,我不介紹了,直接調用,仍是在我很喜歡的Razor裏面

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>

        @{
            WebService.WeatherService.WeatherWS weatherClient = new WebService.WeatherService.WeatherWS();
            string[] text = weatherClient.getWeather("深圳", "");

            foreach (var item in text)
            {
                <text> @item </text>
            }

        }
    </div>
</body>
</html>

不知道發現了沒,這個getWeather接口也是坑,明明兩個參數,一個是城市名,一個是城市的編號ID,可是輸入ID卻沒有身份驗證....因此上面的幾個接口都是獲取Id的有什麼用???我直接輸入城市名就獲取了.....

看看結果

根據下拉框內容更新表格

下拉框怎麼獲取枚舉的值

確定不能寫死數據了,因此從枚舉獲取值最好

<select class="form-control input-sm" id="adjustStatus">
    <option value="-1">調整狀態</option>
    @foreach (var item in Enum.GetValues(typeof(ProductSaleStatus)))
    {
        <option value="@item.GetHashCode()">@item</option>
    }
</select>

獲取表格選擇的Id,下拉框的點擊事件

$('#adjustStatus').on("click", function () {
  if ($('#adjustStatus').val() == -1) {
      return
  }

  id = [];
  $('input[name="checkbox"]:checked').each(function () {
      if ($(this).prop("checked")) {
          id.push($(this).val());
      }
  })

  if (id.length > 0) {
      var ids = id.join(",");
      $.ajax({
          type: "post",
          url: "/ProductSale/AdjustSaleStatus",
          data: { ids: ids, status: $('#adjustStatus').val() },
          success: function (data) {
              if (data.Status == 1) {
                  layer.alert(data.Message, { title: '提示', icon: 1, time: 10000});
                  # 刷新頁面
                  window.location.reload()
              }
          },
          error: Common.Public.Error
      });
  } else {
      layer.alert("請最少選擇一條銷售記錄", { title: '提示', icon: 2, time: 5000, anim: 6 });
  }
    # 最後,把個人下拉框恢復原樣,否則點一次又執行了
  $('#adjustStatus').val(-1)
});

最好的方法

還可使用更好的方法,以下

//這個是HTML
<td>
<select class="adjustStatus">
       @foreach (var item in Enum.GetValues(typeof(ChatMessageStatus)))
        {
              <option value="@item.GetHashCode()" @if ((int)chatMessage.Status == item.GetHashCode()) { <text> selected</text> }>@item</option>
        }
</select>
</td>

//這個是js
        $('.table tbody').on('change', 'tr .adjustStatus', function () {
            $.ajax({
                type: "post",
                url: "/Messenger/AdjustStatus",
                data: { id: $(this).parents("td").attr("id"), status: $(this).val() },
                success: function (data) {
                    if (data.Result == "succeed") {
                        window.location.reload()
                    }
                },
            });
        });

枚舉的值怎麼顯示爲中文

通常來講,枚舉的值在數據庫中都是一個int類型的字段,裏面存儲0123這樣的數字

而後枚舉是相似這樣的,通常都在類上面寫了

public enum People
    {
        許嵩 = 0,
        蜀雲泉 = 1
    }

添加一個枚舉類型的字段,給個默認值

public People people { get; set; } = People.許嵩;

前端頁面使用的時候,直接調用,由於字段自己就是枚舉的,因此顯示的時候顯示的就是中文

<td>@chatMessage.people</td>

Bootstrap的table點擊下一頁js不可使用

使用了Bootstrap的一個table插件,發現點擊下一頁以後,js不起做用了

例如我下面的表格裏面的一個class是people,我直接使用.people不行,下一頁js根本不生效,換成下面那種就能夠了

//$('.people').on("click", function () {
//將上面的換成下面的,就能夠了

$('.table tbody').on('click', 'tr .people' , function () {

查看用戶是從哪一個頁面過來的

if (HttpContext.Current.Request.UrlReferrer != null)
{
    rurl = HttpContext.Current.Request.UrlReferrer.AbsoluteUri;
}

插入數據後返回該數據的id

代碼裏面寫的是bool,我就很奇怪,我還得再寫一個返回int類型的方法?

可是我萬萬沒想到, customer.CustomerId = id;這一行代碼就已經返回了id了

public bool AddCustomer(Customer customer)
        {
            string strSql = @"insert into Customer(company,contact) values (@company,@contact);Select @@Identity";
            DbParameter[] cmdParms = {
                    _helper.CreateInDbParameter("company", DbType.String,customer.Company),
                    _helper.CreateInDbParameter("contact", DbType.String,customer.Contact)};
                    int id = _helper.GetInt(_helper.ExecuteScalar(CommandType.Text, strSql.ToString(), cmdParms));
            customer.CustomerId = id;
            return id > 0;
        }

IIS部署https

在使用push.js進行通知提醒的時候,使用本地的IIS部署的項目沒法測試,由於push.js只能在https這樣的請求頭下工做,因此新加一個IIS部署爲https便可

選擇網站,點擊右側的綁定,出來一個網站綁定,選擇https便可,如圖

選擇https,輸入本機ip,默認443端口,最下面的證書能夠選擇IIS

而後訪問網址直接輸入https://192.168......便可

使用JSON JavaScriptSerializer 進行序列化或反序列化時出錯。字符串的長度超過了爲 maxJsonLength屬性

只須要把代碼改成如下

return new JsonResult() {
    Data = new { total, rows },
    MaxJsonLength = int.MaxValue,
    ContentType = "application/json",
    JsonRequestBehavior = JsonRequestBehavior.AllowGet
};

使用KeyName

使用KeyName真的是太必要了,有的Name裏面是有奇怪的字符的,顯示效果太差,因此須要KeyName

public static string GetKeyName(this string name)
        {
            if (!string.IsNullOrWhiteSpace(name))
            {
                return name.Trim().Replace("~", "-").Replace("`", "-").Replace("!", "-").Replace("@", "-")
                    .Replace("#", "-").Replace("$", "-").Replace("%", "-").Replace("^", "-").Replace("&", "-").Replace("*", "-")
                    .Replace(" ", "-").Replace("(", "-").Replace(")", "-").Replace("+", "-").Replace("®", "-").Replace("™", "-")
                    .Replace("=", "-").Replace(",", "-").Replace(".", "-").Replace("<", "-").Replace(">", "-").Replace("’", "-").Replace(",", "-").Replace("±", "-").Replace("[", "-").Replace("]", "-")
                    .Replace("?", "-").Replace("/", "-").Replace("\\", "-").Replace(";", "-").Replace(":", "-").Replace("–", "-").Replace("ω", "-").Replace("{", "-").Replace("}", "-")
                    .Replace("'", "-").Replace("\"", "-").Replace("「", "-").Replace("」", "-").Replace("|", "-").Replace("_", "-").Replace("---", "-").Replace("--", "-").ToLower().Trim();
            }
            return "";
        }
相關文章
相關標籤/搜索