0%

MVC中很好用的一種驗證方式就是在model寫attribute

1
2
3
4
[Required(ErrorMessage="展覽名稱為必填")]
[MaxLength(50)]
public string ExhibitionName { get; set; }

接著在View中用HtmlHelp方式建立Textbox

1
2
3
@Html.TextBoxFor(m => m.ExhibitionName)
@Html.ValidationMessageFor(m => m.ExhibitionName)

MVC就會很貼心的把你的Client端驗證做好了。

但今天遇到的問題是,用同樣的方法寫在Partial View裡面卻沒有用
狀況如下:
在_layout Page中一樣載入了必備的MVC4提供的Jquery驗證檔案

<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
網站頁面長成這樣
[![](http://4.bp.blogspot.com/-WiQ8PRLsFG0/UX4vwwOgvvI/AAAAAAAACq8/ifNZBq9JUEs/s640/1.png)](http://4.bp.blogspot.com/-WiQ8PRLsFG0/UX4vwwOgvvI/AAAAAAAACq8/ifNZBq9JUEs/s1600/1.png)
當按下紅色框框內的功能列表,用Ajax的方式return Partial View放到藍色框框中。 [![](http://1.bp.blogspot.com/-h-0y5VY6FgE/UX4wNNMxGiI/AAAAAAAACrE/IzSGeMXQhQo/s640/1.png)](http://1.bp.blogspot.com/-h-0y5VY6FgE/UX4wNNMxGiI/AAAAAAAACrE/IzSGeMXQhQo/s1600/1.png) 但用Ajax載入的Partial View用上述的方式就不會自動驗證了,研判應該是動態產生的DOM元件沒有跟JQuery繫結到,這跟以前Asp.Net的UpdatePanel有異曲同工之妙。

所以在Partial View中的Script block中加入這行 註:#ajaxForm為Partial View中Form ID

1
2
3
4
$('body').on("click", '.addNewExihition', function () {
$.validator.unobtrusive.parse('.ajaxForm');
});

這樣JQuery的驗證就又重新繫結上了,讚!!

按下新增按鈕後,利用JQuery動態新增一個填寫欄位跟兩個按鈕


其中取消的按鈕ID為addCancel,我想替它增加click事件按下後彈跳一則簡短的訊息
原本的寫法如下:

1
2
3
4
$('#addCancel').click(function () {
alert('Click事件沒有問題');
});

但Click事件始終沒有效果,原來動態新增的elements要綁定事件需要用**.on**的方式

1
2
3
4
$('body').on("click", '#addCancel', function () {
alert('用on綁定就沒有問題!!');
});

如果有個View同時需要載入兩個model時可以使用tuple ```html
@model Tuple<IEnumerable<NTI.Models.ExhibitionList>,NTI.Models.ExhibitionList>

1
2
3
4
5
6
7
8
9
10
11
12
13
14


**Model**```csharp
public class ExhibitionList
{
[Required]
[MaxLength(50)]
public string ExhibitionName { get; set; }

public DateTime CreateDate { get; set; }

public DateTime EditDate { get; set; }
}

Controller```csharp
public ActionResult ExhibitionList()
{
var tuple = new Tuple<IEnumerable, ExhibitionList>(Repository.GetExhibitionList(), new ExhibitionList());
return PartialView(tuple);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

**View**```html
if (Model.Item1.Count() == 0)
{
<tr id="noExhibition">
<td colspan="4">
<span class="text-left">沒有建立任何展覽喔....</span>
</td>
</tr>
}
else
{
foreach (var exhibitionItem in Model.Item1)
{
<tr>
<td>1</td>
<td>@exhibitionItem.ExhibitionName</td>
<td>@exhibitionItem.CreateDate</td>
<td>@exhibitionItem.EditDate</td>
</tr>
}
@Html.TextBoxFor(m => Model.Item2.ExhibitionName)
}

在View中使用Model的方法為:
Model.Item1代表載入的第一個Model
Model.Item2代表載入的第二個Model

第二種方式就是建立一個ViewModel的方式
Model```csharp
/// 展覽列表的ViewModel
public class ExhibitionListViewModel
{
public IEnumerable IEmumerable_ExhibitionList { get; set; }
public ExhibitionList ExhibitionListModel { get; set; }
}

1
2
3
4
5
6
7
8
9
**View**```csharp
public ActionResult ExhibitionList()
{
ExhibitionListViewModel model = new ExhibitionListViewModel();
model.IEmumerable_ExhibitionList = Repository.GetExhibitionList();
model.ExhibitionListModel = new ExhibitionList();
return PartialView(model);
}

Controller```csharp
@Html.TextBoxFor(model => model.ExhibitionListModel.ExhibitionName)
@Html.ValidationMessageFor(model => model.ExhibitionListModel.ExhibitionName)

//and ….
if (Model.IEmumerable_ExhibitionList.Count() == 0)
{
//do something
}


將狀態還原到當時的commit ```csharp
git reset “編碼”

1
2
3
4

將判斷現在source code的狀態 ```csharp
git status

將改變過的source code全部add進去 ```csharp
git add .

1
2
3
Commit ```csharp
git commit -m "名稱"

push ```csharp
git push origin master


今天遇到一個需求如下
Table1 T1
裡面有問候語加上一群使用者的代碼(用逗號區隔開來)

Table1 T2
裡面有使用者代碼跟其對應的名稱

目標搜尋出來的結果如下:
意即代碼要被換成其對應的名稱

首先先建立一個可以將分隔符號拆開,並且去搜尋對應名稱的function (抓網路上高手寫的Code回來修改而成) ```sql
create FUNCTION [dbo].[ufn_Split]( @InputString nvarchar(4000))
RETURNS varchar(1000) –執行這個function會回傳字串
AS
BEGIN
–用來儲存分隔符號的Index
DECLARE @CIndex smallint
–用來串接字串並最後回傳回去的字串
declare @OutputString varchar(1000) =’’
declare @tempString varchar(500) =’’

WHILE (@InputString<>’’)
BEGIN
SET @CIndex=CHARINDEX(‘,’,@InputString) –抓到第一個分隔符號的Index
IF @CIndex=0 SET @CIndex=LEN(@InputString)+1

–將第一組代碼拆解出來並帶到T2去搜尋對應的名稱,如果搜尋出來為null的話則當作空字串處理
set @tempString = isnull((select name from t2 where id = (SUBSTRING(@InputString,1,@CIndex-1))),’’)

–這串if else純粹只是要解決多餘的逗號問題而已,就不多加解釋了
if @tempString <> ‘’
begin
if @OutputString = ‘’
begin
set @OutputString = @tempString
end
else
set @OutputString = @OutputString +’,‘+@tempString
end

IF @CIndex=LEN(@InputString)+1 BREAK

–把剛剛搜尋過的代碼挑掉後,剩下的繼續跑迴圈
SET @InputString=SUBSTRING(@InputString,@CIndex+1,LEN(@InputString)-@CIndex)
END
RETURN @OutputString
END

1
2
3
4

最後SQL command如下,就可以得到上述合併的結果了!!! ```sql
select title,dbo.ufn_Split(number) from t1

今天練習在MVC4中使用Forms Authentication的驗證機制來控制登入與否的狀態,記錄一下筆記

  • 首先打開MVC的web.config找到authentication的標籤將登入頁面註冊一下 ```csharp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

只要在沒有登入的情況下瀏覽需要權限的頁面就會被導到/BackStage/Login,要求其登入* 接下來設定哪些action需要權限才能觀看,在MVC4中的設定方式如下
* 第一種:直接在要action上面加上[Authorize],表示該action匿名的方式無法存取
```csharp
public class ExhibitionController : Controller
{
//
// GET: /Exhibition/
[Authorize]
public ActionResult Index()
{
return View();
}
}

  • 第二種:在Controller加上[Authorize],表示所有這個controller底下的action皆需要驗證通過的狀態下才能讀取,可以在action加上 [AllowAnonymous]讓該action不用驗證

    [Authorize]//預設這個controller都要驗證過後才能讀取
    public class ExhibitionController : Controller
    {
    [AllowAnonymous]//這個action無需驗證,所有人皆能直接讀取
    public ActionResult Index()
    {
      return View();
    
    }
    public ActionResult about()
    {
      return View();
    
    }
    }
     </pre>
    
  • 驗證成功後呼叫FormsAuthentication.RedirectFromLoginPage(),告訴網站該使用者已經通過驗證。 ```csharp
    if (Acclogin.CheckPassword())
    { FormsAuthentication.RedirectFromLoginPage(Acclogin.Account, false);
    return Redirect(returnUrl);
    }

要使用SQL的PWDCOMPARE 函數,必須先將邏輯寫進StoreProcedure或是SQL function裡面,這裡以StoreProcedure為例

  • 先建立StoreProcedure在裡面使用PWDCOMPARE函數比對密碼是否正確,成功傳回1,失敗傳回0
create procedure sp_CheckLoginPassword
 @Account varchar(50),
 @Password varchar(150)
as
 declare @validate int
 set @validate = (
 select PWDCOMPARE(@Password,tcuser.Password)
 from tcuser
 where tcuser.Account = @Account) select isnull(@validate,0)
* 建立Entity Framwork,將剛剛寫的StoreProcedure更新進來

  • 透過Entity Framwork建立出來的物件呼叫該方法就大功告成了!!

    public bool CheckPassword()
    {
    //傳回0表示驗證失敗; 1表示成功
    NTIEntities db = new NTIEntities();
    bool isValidate = db.sp_CheckLoginPassword(this.Account, this.Password).First() == 1 ? true : false;
    return isValidate;
    }
  • 驗證方法成功後呼叫FormsAuthentication.RedirectFromLoginPage(),告訴網站該使用者已經成功登入 ```csharp
    if (Acclogin.CheckPassword())
    { FormsAuthentication.RedirectFromLoginPage(Acclogin.Account, false);
    return Redirect(returnUrl);
    }

在SharePoint 2013中,預設沒有切換使用者的選項

https://1.bp.blogspot.com/-3Fzzh6KvIog/UWvXRQFmtgI/AAAAAAAACYE/M96nwlEF1gs/s1600/111.png

叫出來的方法如下:

  • 先找到以下路徑開啟 \15\TEMPLATE\CONTROLTEMPLATES\Welcome.ascx
    https://2.bp.blogspot.com/-XTar0tN4fs4/UWvY1NbOs2I/AAAAAAAACYQ/IZLGfEJyrOA/s1600/11.png
  • 用編輯器打開,並找到ID為 ID_RequestAccess的控制項
    https://2.bp.blogspot.com/-foGebgpfQQU/UWvZvzG7kxI/AAAAAAAACYg/Ft0kIEB-Ejg/s1600/11.png
  • 在該控制項前面加入以下程式碼
    1
    2
    3
    4
    5
    6
    <SharePoint:MenuItemTemplate  runat="server"  ID="ID_LoginAsDifferentUser"
    Text="<%$Resources:wss,personalactions_loginasdifferentuser%>"
    Description=" <%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
    MenuGroupId="100"
    Sequence="100"
    UseShortId="true" />
    https://3.bp.blogspot.com/-FDGUOFCxbhs/UWvarNajT7I/AAAAAAAACYs/iLMMk-yB1tw/s1600/11.png
  • 大功告成
    https://4.bp.blogspot.com/-uFjLjbAQEO0/UWva_j6HqfI/AAAAAAAACY0/2ELRqrG5QS8/s1600/11.png

GridView原本產出的資料如下圖

[![](http://2.bp.blogspot.com/-Spka-CC-RXA/UQne4vnVBtI/AAAAAAAAA1c/vq-CaRzXOyI/s1600/%E6%9C%AA%E5%91%BD%E5%90%8D.png)](http://2.bp.blogspot.com/-Spka-CC-RXA/UQne4vnVBtI/AAAAAAAAA1c/vq-CaRzXOyI/s1600/%E6%9C%AA%E5%91%BD%E5%90%8D.png)
需求是將*號的部分變成TextBox且可輸入的字數要跟*號的個數相同,程式碼如下:

在GridView RowDataBound事件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
for(int i = 0 ; i = < e.Row.Cells.Count; i++)
{
if(e.Row.Cells[i].Text.Contains("*"))
{
int count = e.Row.Cells[i].Text.Count(f => f== '*');
int firstIndex = e.Row.Cells[i].Text.IndexOf('*');

e.Row.Cells[i].Text = e.Row.Cells[i].Text.Replace("*","").Insert(firstIndex, "<input maxlength="+ count +" runat='server' size='5' type='text' value='' />");
}
}
}
}

  1. 先算出*號的個數
  2. 找到*號第一次出現的位置
  3. 將*號全部Replace並在第一次出現的位置插入<input type=’text’ />
    結果如下
    [![](http://2.bp.blogspot.com/-e8AUIv9UIiU/UQnhfaf2eUI/AAAAAAAAA1w/cKFgnpj4UIE/s1600/%E6%9C%AA%E5%91%BD%E5%90%8D.png)](http://2.bp.blogspot.com/-e8AUIv9UIiU/UQnhfaf2eUI/AAAAAAAAA1w/cKFgnpj4UIE/s1600/%E6%9C%AA%E5%91%BD%E5%90%8D.png)

在GridView的Pager是用Table組成的,這裡是做個簡單的將 "..." 改成前五頁後五頁。
else if(e.Row.RowType == DataControlRowType.Pager)
        {
            //修改page ...的樣式
            TableRow pageTR = (TableRow)e.Row.Controls[0].Controls[0].Controls[0];
            for(int x = 0; x< pageTR.Controls.Count; x++)
            {
                TableCell pageTD = (TableCell)pageTR.Controls[x];
                for(int y = 0 ; y<pageTD.Controls.Count; y++)
                {
                    if(pageTD.Controls[y] is LinkButton)
                    {
                        LinkButton lb = (LinkButton)pageTD.Controls[y];
                        if(lb.Text == "..." &&  x == 1)
                        {
                            lb.Text = "前5頁";
                        }
                        else if(lb.Text =="...")
                        {
                            lb.Text = "後5頁";
                        }
                    }
                }
            }
        }