精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。”需要全文内容也请联系孙老师。
在本文将分享如何使用ASP.NET MVC、jQuery、Web API、Bootstrap、AngularJS和AngularUI Bootstrap来实现警告横幅和可重用的Modal。有些人将警告栏标示为免责声明横幅、同意屏幕、启动画面、系统可接受使用政策、登录警告横幅、登录政策、登录横幅和登录通知等。基本上,它是页面也是一个通知,当用户首次访问或登录到应用程序时显示。本文摘要如下。
图1显示了Solution包含两个项目,分别是CommonApp和WarningBanner。CommonApp是一个简单的WebAPI项目,负责返回警告横幅内容。
图1
清单1显示了WarningPage视图中的Bootstrap模式标记。在此示例中,将从ViewBag中读取模态体的内容。您可以将其更改为从模型绑定,或根据您的要求将横幅内容硬编码到页面上。数据键盘设置为“假”,以防止用户通过按键盘上的ESC键关闭警告横幅。
清单1
Html.RenderPartial("~/Views/Shared/_AntiforgeryToken.cshtml"); }
<div class="modal fade" id="myModal" role="dialog" data-keyboard="false" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
@if (ViewBag.SystemWarningMessage != null)
{
<div class="modal-body"> @Html.Raw(ViewBag.SystemWarningMessage)</div>
}
<div class="modal-footer">
<button type="button" class="btn btn-default" id="btnAcceptPolicy" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
在页面加载时,WarningPage操作方法将检查用户是否在警告横幅页面上单击确定按钮。如果是,将请求重定向到主页,否则获取警告横幅消息并将其显示在页面上。
清单2
public ActionResult WarningPage() { if (Session["SessionOKClick"] != null)
{
return RedirectToAction("Index");
}
SetWarningBanner();
return View();
}
清单3中显示的是设置警告横幅内容的代码。在此示例中,该方法通过HttpClient类从Web API获取内容。代码非常简单,但是我们可以在这里做一些改进。该代码可以修改为从配置文件读取Web API URI,并在将JSON返回给客户端之前对其进行清理。如果Web API不是首选,那么我们可以修改代码以从数据库/实体、配置文件中读取内容,甚至硬编码。此方法中缓存控制头的目的是防止浏览器后退按钮从缓存中提供内容。例如,如果用户在接受策略后点击浏览器后退按钮,
清单3
internal void SetWarningBanner()
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
Response.Cache.SetNoStore();
//Content can be from the database/Entity, Web Services, hardcode here
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:47503");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("api/warningbanner/1").Result;
if (response.IsSuccessStatusCode)
{
string responseString = response.Content.ReadAsStringAsync().Result;
JObject json = JObject.Parse(responseString);
//you can update the code to sanitize the json output here
ViewBag.SystemWarningMessage = json["Content"].ToString();
}
}
}
清单4显示了警告横幅Web API控制器的内容。此类包含一个WarningBanner对象,其中包含几个示例数据,以及一个Get方法,以通过id 检索WarningBanner。再次,请随意修改此代码以从数据库/实体、配置文件等读取数据。
清单4
public class WarningBannerController : ApiController
{
//sample data
IList<WarningBanner> warningBanners = new List<WarningBanner>
{
new WarningBanner { Id = 1, Content = "<b> *** Warning Banner Content 1 ****</b>",
LastUpdatedDate = DateTime.Now},
new WarningBanner { Id = 2, Content = "<b> *** Warning Banner Content 2 ****</b>",
LastUpdatedDate= DateTime.Now.AddDays(-30)}
};
public IHttpActionResult Get(int id)
{
var banner = warningBanners.FirstOrDefault((p) => p.Id == id);
if (banner == null)
{
return NotFound();
}
return Ok(banner);
}
}
清单5显示了,在Ok按钮上单击,Ajax调用将被触发,发送post到Home / AcceptPolicy方法。在该示例中,该post将包括防伪令牌和键值对数据。如果请求成功,请求将被重定向到最初请求的页面。
清单5
<script type="text/javascript">
$(window).load(function () {
$('#myModal').modal('show');
});
jQuery(document).ready(function () {
jQuery("#btnAcceptPolicy").click(function () {
jQuery.ajax({
type: "POST",
url: '@Url.Content("~/Home/AcceptPolicy")',
data: { rURL: 'someDummyValue' },
beforeSend: function (xhr) { xhr.setRequestHeader('RequestVerificationToken', $("#antiForgeryToken").val()); }, success: function (data) {
window.location.href = data;
}
});
});
});
</script>
该AcceptPolicy操作方法被饰以HttpPost和AjaxValidateAntiForgeryToken属性。这种方法的主要目的是告诉客户端将请求重定向到哪个URL,用户点击Ok按钮后。请参阅清单6。您还可以通过添加额外的逻辑将用户响应记录到数据库中来做些创新。该方法接受一个参数rURL,代码不使用该变量。目标是演示AJAX文章可以将参数传递给action方法。SessionOKClick会话变量的目的是跟踪用户是否点击了确定按钮。另一方面,SessionReturnUrl会话变量包含初始页面请求的URL。
清单6
[HttpPost]
[AjaxValidateAntiForgeryToken]
public ActionResult AcceptPolicy(string rURL)
{
Session["SessionOKClick"] = "1";
string decodedUrl = string.Empty;
//return url to redirect after user accepted the policy
if (Session["SessionReturnUrl"] != null)
{
decodedUrl = Server.UrlDecode(Session["SessionReturnUrl"].ToString());
}
if (Url.IsLocalUrl(decodedUrl))
{
return Json(decodedUrl);
}
else
{
return Json(Url.Action("Index", "Home"));
}
}
清单7显示了自定义的授权过滤器,以便在授权用户调用操作方法之前,检查请求是否需要重定向到警告横幅页面。在此示例中,OnAuthorization方法仅包含处理警告横幅策略的逻辑。实际上,您的应用程序可能有其他逻辑来验证授权用户。我们可以将清单7中的代码附加/合并到应用程序授权过滤器类中。该PageToSkipPolicyNotification和PageToShowPolicyNotification方法允许指定特定页面跳过或分别显示警告标志页。该OnAuthorization方法将请求重定向到警告页面,如果
回想起来,SessionOKClick会话变量被设置为WarningPage AcceptPolicy Action方法。SessionReturnUrl会话变量的目的是保存请求的URL。我们不能指望所有用户通过/ home页面进入Web应用程序,有些可能从/ home /联系页面,/ home / about页面等进入。让我们说用户最初从/ home进入Web应用程序/联系页面。用户单击警告页面上的确定按钮(AcceptPolicy)后,请求将被重定向到/ home /联系页面。如果要使用AngularJS查看警告横幅,请在web.config的appSettings元素中将WaningBannerAngular值设置为1。
清单7
public class RequireAcceptPolicy : AuthorizeAttribute, IAuthorizationFilter
{
internal static bool PageToSkipPolicyNotification(HttpContext ctx)
{
string[] pagesToExclude = { "/home/testwarningpage", "/home/warningpage"};
string pageToCheck = ctx.Request.Path.ToString().ToLower().TrimEnd('/');
return pagesToExclude.Contains(pageToCheck) ? true : false;
}
internal static bool PageToShowPolicyNotification(HttpContext ctx){ ….}
public override void OnAuthorization(AuthorizationContext filterContext)
{
//Other Authorization logic ….
….
//don't prompt if the action is from acceptpolicy, and pages to exclude and SessionOKClick != null (user already accepted policy)
if (!filterContext.ActionDescriptor.ActionName.ToLower().Contains("acceptpolicy") && !PageToSkipPolicyNotification(HttpContext.Current) && HttpContext.Current.Session["SessionOKClick"] == null)
{
//track the request url, include the query string
HttpContext.Current.Session["SessionReturnUrl"] = filterContext.HttpContext.Request.Url.PathAndQuery;
//redirect to policy page
if (System.Configuration.ConfigurationManager.AppSettings["WaningBannerAngular"] == "1")
{
filterContext.Result = new RedirectResult("~/home/WarningPageNg");
}
else
{
filterContext.Result = new RedirectResult("~/home/WarningPage");
}
}
}
} } } }
清单8显示了如何将自定义授权过滤器属性RequireAcceptPolicy添加到全局过滤器集合。
清单8
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new RequireAcceptPolicy());
}
}
防伪令牌代码是来自于使用Ajax Post传递防伪令牌到MVC操作。不将客户端相关的代码放在每个页面上,而是将代码放置在部分视图_AntiforgeryToken.cshtml中。您可以将需要防伪令牌的部分视图放在单个页面或布局页面中。列表9中显示的是_AntiforgeryToken.cshtml的内容。部分视图分别包含ID为antiForgeryToken和antiForgeryTokenNg的两个隐藏字段。隐藏的字段保存由GetAntiForgeryToken方法生成的反伪造令牌。AngularJS使用了antiForgeryTokenNg隐藏字段。
清单9
@functions{
public string GetAntiForgeryToken()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + "," + formToken;
}
}
<input type="hidden" id="antiForgeryToken" value="@GetAntiForgeryToken()" />
<input id="antiForgeryTokenNg" data-ng-model="antiForgeryToken" type="hidden" data-ng-init="antiForgeryToken='@GetAntiForgeryToken()'" />
清单10显示了如何将jQuery AJAX post将Anti-Forgery令牌传递给Controller Action方法。您可以清单5看到完整的JavaScript。
清单10
beforeSend: function (xhr) { xhr.setRequestHeader('RequestVerificationToken', $("#antiForgeryToken").val()); }
清单11简要显示了AngularJS如何将Anti-Forgery令牌传递给Controller Action方法。请下载源代码,因为我可能会跳过本节中的内容。在页面加载时,Controller将从隐藏字段读取令牌,然后将其存储到数组变量items中。当用户单击接受策略/确定按钮时,AngularJS $ http服务将发布到服务器,包括headers属性。在此示例中,头文件属性包含RequestVerificationToken参数和$ scope.items [0]中的值。这个例子中的数组恰好只有一个项目,这也是位置为0的原因。
清单11
// modal controller
$scope.items = [$scope.antiForgeryToken];
// OK click
$http({
method: 'POST',
url: '/home/AcceptPolicy',
params: Indata,
headers: {
'RequestVerificationToken': $scope.items[0]
}
…
清单12显示了WarningPageNg视图中的AngulatJS和AngularUI Bootstrap模式标记。像WarningPage视图一样,模态体的内容来自ViewBag。您可以将其更改为从模型绑定,或根据您的要求将横幅内容硬编码到页面上。模式的内容封装在脚本指令下的模板中。OK按钮单击路由到ok()函数,openModal()函数将在页面加载时调用。
清单12
<div ng-controller="modalcontroller">
<script type="text/ng-template" id="myModal.html">
<div class="modal-header"></div>
<div class="modal-body">
@if (ViewBag.SystemWarningMessage != null)
{
<div class="modal-body"> @Html.Raw(ViewBag.SystemWarningMessage)</div>
}
</div>
<div class="modal-footer">
<button class="btn btn-default" type="button" ng-click="ok()">OK</button>
</div>
</script>
@{ Html.RenderPartial("~/Views/Shared/_AntiforgeryToken.cshtml"); }
<span ng-init="openModal()"></span>
</div>
@section scripts{
<script src="~/ControllersNg/ModalController.js"></script>
}
清单13中显示的是ModalController.js文件的内容。最初,代码将创建一个新的模块,即TestAngularApp,并声明对ui.bootstrap模块的依赖。然后,代码将利用Config函数将$ httpProvider提供程序注入应用程序中的模块配置块。提供者将允许该模块向已执行的呼叫添加“X-Requested-With”类型的头。此标头必须与AjaxValidateAntiForgeryToken属性配合使用,并解决错误“所需的反伪造cookie\”__ RequestVerificationToken \“不存在”。您可以在这里看到AngularUI Modal打开的属性和定义的列表。
清单13
var app = angular.module('TestAngularApp', ['ui.bootstrap']); app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
app.controller('modalcontroller', function ($scope, $uibModal) {
$scope.animationsEnabled = true;
$scope.openModal = function (size) {
$scope.items = [$scope.antiForgeryToken];
var ModalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModal.html',
controller: 'InstanceController',
backdrop: false,
resolve: {
items: function () { return $scope.items; }
}
});
};
});
app.controller('InstanceController', function ($scope, $uibModalInstance, $http, $window, items) {
$scope.items = items;
$scope.ok = function () {
var Indata = { rURL: 'dummyTestParam' };
$http({
method: 'POST',
url: '/home/AcceptPolicy',
params: Indata,
headers: {'RequestVerificationToken': $scope.items[0] }
}).then(function successCallback(response) {
$scope.status = response.status;
$scope.data = response.data;
$window.location.href = response.data;
}, function errorCallback(response) {
});
$uibModalInstance.close();
};
$scope.cancel = function () {
//it dismiss the modal
$uibModalInstance.dismiss('cancel');
};
});
列表14中显示的是_ModalDialog部分视图的HTML标记。在这个视图中,有Modal对话框标题和正文以及几个按钮的占位符。
清单14
id="SharedModalDialogBtnOk" data-dismiss="modal">OK</button>
<button type="button" class="btn btn-default"
id="SharedModalDialogBtnCancel" data-dismiss="modal">Cancel</button>
<div>
</div>
</div>
</div>
清单15显示了在_ModalDialog部分视图中显示对话框的jQuery插件,即ModalDialog。该插件可以接受五个参数,您可以根据需要进行自定义。标题和主体参数对应于对话标题和正文内容。该OkButtonText和CancelButtonText参数将决定标签和OK的知名度,并分别取消按钮。如果指定了OkClickRedirect值,请求将被重定向到指定的URL,点击OK按钮。
清单15
清单16显示了如何利用新创建的部分视图和jQuery插件来显示模态对话框。该RenderPartial方法可以用在布局网页内。如果应用程序需要在整个应用程序中向客户端显示简单的警报消息/通知,这将非常有用。有三个按钮,插件使用示例在清单16。
清单16
清单17显示了如何在页面加载或没有按钮点击事件时显示对话框。
清单17
列表18中显示了_ModalDialogNg.html文件中的模态对话框模板。按钮可见性基于ngShow属性中的表达式,分别为showX、showOK和showCancel。标题和按钮标签可以通过范围类的属性访问。AngularJS ng-bind-html指令正用于在div元素中安全地显示HTML内容。但是,在显示之前,请确保清理用户输入。
清单18
清单19显示了ModalPartialController.js文件的内容。AngularJS $ sce(严格上下文转义)服务正在控制器中使用以构建受信任的HTML值。$ uibModal是一种创建模式窗口的服务。$窗口服务的目的是将请求重定向到OK按钮上的特定URL。隐藏或显示按钮,设置元素标签和值的逻辑嵌入在列表19中。
清单19
var app = angular.module('TestAngularApp', ['ui.bootstrap']);
app.controller('modalcontroller', function ($scope, $uibModal, $window) {
$scope.openModal = function (title, body, okBtnText, okClickRedirect, cancelBtnText) {
$scope.items = [title, body, okBtnText, okClickRedirect, cancelBtnText];
var ModalInstance = $uibModal.open({
animation: true,
templateUrl: '/TemplatesNg/_ModalDialogNg.html',
controller: 'InstanceController',
backdrop: false, //disables modal closing by click on the background
keyboard: true, //disables modal closing by click on the ESC key
resolve: {
items: function () {
return $scope.items;
}
}
});
ModalInstance.result.then(function (btn) {
if (btn == "OK") {
$window.location.href = okClickRedirect;
}
}, function () { });
};
});
app.controller('InstanceController', function ($scope, $uibModalInstance, $sce, items) {
$scope.items = items;
$scope.title = $scope.items[0];
$scope.body = $scope.items[1];
$scope.btnOkText = $scope.items[2];
$scope.btnCancelText = $scope.items[4];
var returnUrl = $scope.items[3];
//allow html
$scope.htmlBind = $sce.trustAsHtml($scope.items[1]);
//hide or close the X close button on the top, you can write extra logic here to hide or show it
$scope.showX = false;
$scope.showOK = true;
if ($scope.btnOkText == '') {
//hide OK button
$scope.showOK = false;
}
//cancel button
$scope.showCancel = true;
if ($scope.btnCancelText == '') {
$scope.showCancel = false;
}
//OK clicked
$scope.ok = function () {
if (returnUrl == '') {
$uibModalInstance.close('');
} else {
$uibModalInstance.close('OK');
}
};
$scope.cancel = function () {
//it dismiss the modal
$uibModalInstance.dismiss();
};
});
清单20显示了应用程序/视图如何通过传递不同的参数来调用AngularUI Bootstrap Modal。首先,包括ModalPartialController.js,从列表19到页面的AngularJS控制器。然后创建一个div元素,并将ng-controller指令与控制器类modalcontroller作为其值。在div元素和ng-click事件中添加一个按钮,指定在控制器(ModalPartialController.js)中定义的openModal方法。
清单20
ng-click="openModal('AngularUI Model','Click on <b>Ok</b> to Redirect to Contact page.', 'OK', '/home/Contact', 'Close')">
Modal with redirect</button>
</div>
<div ng-controller="modalcontroller">
<button class="btn btn-default" type="button"
ng-click="openModal('@ViewBag.Something','This is the content<b>body 2</b>', '','', 'Close It')">
Modal with close button only</button>
</div>
<div ng-controller="modalcontroller">
<button class="btn btn-default" type="button"
ng-click="openModal('AngularUI Model 2','This is a notification!', '','', 'Ok')">
Modal with OK button only
</button>
</div>
@section scripts{
<script src="~/ControllersNg/ModalPartialController.js"></script>
}
清单21显示了如何在页面加载或没有按钮单击事件时显示对话框。
清单21
ng-init="openModal('AngularUI Model Onload','Display on page load!', '','', 'Ok')">
</div>