在Web应用中实现用户反馈机制

在Web应用开发中,用户在提交表单后,通常需要得到一个视觉反馈,以确认操作是否成功。本文将探讨如何利用ASP.NET MVC框架中的TempData来实现这一功能。TempData是一个键值存储,用于在当前请求和下一个请求期间保存数据。这意味着可以在POST操作执行时存储一个成功消息,如果操作成功,该消息将在重定向到GET操作时仍然可用。这种模式被称为PRG(Post-Redirect-Get),它有助于保护数据的完整性,并避免用户在刷新页面时重复提交表单。

实现用户反馈机制的步骤

要实现用户反馈机制,需要完成以下步骤:

1. 创建一个Notifier类来存储消息。

2. 通过Action Filter将消息写入TempData

3. 创建一个Html Helper来从TempData读取并显示消息。

4. 将INotifier接口注入到控制器中。

5. 提供写入成功、警告和错误消息的方法。

Notifier类是一个简单直接的类,它包含一个消息列表和不同严重性级别的消息添加方法。每个消息都有一个Generate方法,允许每个消息创建自己的显示标记。

public enum MessageSeverity { None, Info, Success, Warning, Danger } public class Message { public MessageSeverity Severity { get; set; } public string Text { get; set; } public string Generate() { var isDismissable = Severity != MessageSeverity.Danger; if (Severity == MessageSeverity.None) Severity = MessageSeverity.Info; var sb = new StringBuilder(); var divTag = new TagBuilder("div"); divTag.AddCssClass("alert fade in"); divTag.AddCssClass("alert-" + Severity.ToString().ToLower()); var spanTag = new TagBuilder("span"); spanTag.MergeAttribute("id", "MessageContent"); if (isDismissable) { divTag.AddCssClass("alert-dismissable"); } sb.Append(divTag.ToString(TagRenderMode.StartTag)); if (isDismissable) { var buttonTag = new TagBuilder("button"); buttonTag.MergeAttribute("class", "close"); buttonTag.MergeAttribute("data-dismiss", "alert"); buttonTag.MergeAttribute("aria-hidden", "true"); buttonTag.InnerHtml = "×"; sb.Append(buttonTag.ToString(TagRenderMode.Normal)); } sb.Append(spanTag.ToString(TagRenderMode.StartTag)); sb.Append(Text); sb.Append(spanTag.ToString(TagRenderMode.EndTag)); sb.Append(divTag.ToString(TagRenderMode.EndTag)); return sb.ToString(); } } public interface INotifier { IList Messages { get; } void AddMessage(MessageSeverity severity, string text, params object[] format); } public class Notifier : INotifier { public IList Messages { get; private set; } public Notifier() { Messages = new List(); } public void AddMessage(MessageSeverity severity, string text, params object[] format) { Messages.Add(new Message { Severity = severity, Text = string.Format(text, format) }); } }

每个消息都会生成一个Bootstrap警告框,严重性级别允许改变背景颜色。

已经完成了第一步,现在需要在视图中显示这些消息。通过一个Action Filter将消息添加到TempData中,然后在视图中通过一个扩展方法读取它们。

public static class Constants { public const string TempDataKey = "Messages"; } public class NotifierFilterAttribute : ActionFilterAttribute { public INotifier Notifier { get; set; } public override void OnActionExecuted(ActionExecutedContext filterContext) { var messages = Notifier.Messages; if (messages.Any()) { filterContext.Controller.TempData[Constants.TempDataKey] = messages; } } } public static class NotifierExtensions { public static void Error(this INotifier notifier, string text, params object[] format) { notifier.AddMessage(MessageSeverity.Danger, text, format); } public static void Info(this INotifier notifier, string text, params object[] format) { notifier.AddMessage(MessageSeverity.Info, text, format); } public static void Success(this INotifier notifier, string text, params object[] format) { notifier.AddMessage(MessageSeverity.Success, text, format); } public static void Warning(this INotifier notifier, string text, params object[] format) { notifier.AddMessage(MessageSeverity.Warning, text, format); } public static MvcHtmlString DisplayMessages(this ViewContext context) { if (!context.Controller.TempData.ContainsKey(Constants.TempDataKey)) { return null; } var messages = (IEnumerable)context.Controller.TempData[Constants.TempDataKey]; var builder = new StringBuilder(); foreach (var message in messages) { builder.AppendLine(message.Generate()); } return builder.ToHtmlString(); } private static MvcHtmlString ToHtmlString(this StringBuilder input) { return MvcHtmlString.Create(input.ToString()); } }

DisplayMessages方法需要ViewContext以便访问TempData。需要使用相同的键来访问TempData中的消息。为了避免使用“魔术字符串”,添加了TempData键作为常量。还添加了一些方便的扩展方法快捷方式,用于不同类型的消息。

最后一步是将Notifier连接到DI容器。使用流行的DI容器Autofac。如果不熟悉Autofac,他们有很棒的文档。

using Autofac; using Autofac.Integration.Mvc; public class MvcApplication : HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); var builder = RegisterDependencies(); var container = builder.Build(); var mvcResolver = new AutofacDependencyResolver(container); DependencyResolver.SetResolver(mvcResolver); } private static ContainerBuilder RegisterDependencies() { var builder = new ContainerBuilder(); var currentAssembly = Assembly.GetExecutingAssembly(); builder.RegisterType().AsImplementedInterfaces().InstancePerRequest(); builder.RegisterType().AsActionFilterFor().PropertiesAutowired(); builder.RegisterFilterProvider(); builder.RegisterControllers(currentAssembly); return builder; } }

主要需要注意的是,在注册过滤器时,包括了PropertiesAutowired()。这确保了过滤器中的Notifier属性被连接起来。

public class HomeController : Controller { private readonly INotifier notifier; public HomeController(INotifier notifier) { this.notifier = notifier; } public ActionResult NotifyTest() { return View(); } [HttpPost] public ActionResult NotifyTest(FormCollection form) { notifier.Success("一个成功消息"); return RedirectToAction("NotifyTest"); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485