如何使用Ninject 3在MVC 5中实现全局消息传递系统? 我想要实现的目标很简单:
我想添加一条消息,例如:“您已成功完成任务”并将其读入_Layout视图。我会使用ViewBag,ViewData或TempData。问题在于,为了分离问题,我在控制器范围之外做了很多处理逻辑(通过依赖注入)。这意味着ViewBag,ViewData和TempData是不可能的(除非我使用Controller扩展注入的类)
所以我尝试创建一个处理任务的全局静态类。问题是该类向应用程序的所有用户显示,而与其身份验证无关。
答案 0 :(得分:2)
大部分功劳都来自asp.net论坛和他的帖子Send Success Message to View using TempData
您可以在上面的链接中查看他的帖子。代码主要是相同的,我只是修剪了一些我不需要的功能,最后,我使用的是Ninject而不是Autofac(这是使用的IoC容器级别)
<强>目的:强> 当使用Ninject 3作为IoC容器时,您希望使用ASP.NET MVC 5实现全局消息传递系统。
在开始之前,我将假设以下内容:
<强>解决方案:强>
第一。在解决方案上创建一个新文件并将其命名为“MessageSystem.cs”这是将保存我们的消息的类文件。
第二。使用以下代码填写:
public class MessageSystem
{
//This is for bootstrap. This will reference what type of alert we will throw.
public MessageType Type { get; set; }
//Where the message you want to say will be held
public string Message { get; set; }
//Creates the HTML string.
//This outputs the div in HTML with the current message formatted.
public string Generate()
{
//Div Tag
var divTag = new TagBuilder("div");
divTag.AddCssClass("alert alert-" + Type.ToString());
divTag.InnerHtml = Message + "<span class=\"glyphicon glyphicon-remove js-close\"></span>";
return divTag.ToString();
}
}
//The bootstrap alert types.
public enum MessageType
{
success,
info,
warning,
danger
}
上面的类负责生成显示消息所需的HTML。请注意,这样做是为了防止在视图中进行最少的篡改。
第三。我们将创建一个Notifier类,它将负责存储消息并添加它们。我们也抓住机会并创建它的界面。这将是稍后注入的人。
public interface INotifier
{
IList<MessageSystem> Messages { get; }
void AddMessage(MessageType type, string Message);
}
/**
* public class Notifier : INotifier
*
* Purpose: Main class which will take care of adding the messages for us.
*
* */
public class Notifier : INotifier
{
//List of messages so we can display multiple for the user.
public IList<MessageSystem> Messages { get; private set; }
public Notifier()
{
Messages = new List<MessageSystem>();
}
//Adds the message to the current Messages variable.
public void AddMessage(MessageType type, string Message)
{
Messages.Add(new MessageSystem
{
Type = type,
Message = Message
});
}
}
Notifier类有一个公共IList项,负责保存所有消息,以防我们想向用户显示多条消息!
构造函数:Notifier()负责为IList提供List()的实例,以便稍后我们可以添加消息。
//Just for convenience and a placeholder
//Since I will need to use the TempDataKey
//multiple times, it's more convenient to put it as a const.
public static class ConstKeys
{
public const string TempDataKey = "Messages";
}
/**
* public static class NotifierExtensions
*
* Purpsoe: This isn't extremely necessary, it's just a helper that will simplify things
* quite a bit. This will allow you to create a layer of decoupleness which you
* can change later on.
*
* In other words, this will allow you to add the message with the MessageType according
* to the scenario.
*
* */
public static class NotifierExtensions
{
public static void Error(this INotifier notifier, string text)
{
notifier.AddMessage(MessageType.danger, text);
}
public static void Info(this INotifier notifier, string text)
{
notifier.AddMessage(MessageType.info, text);
}
public static void Success(this INotifier notifier, string text)
{
notifier.AddMessage(MessageType.success, text);
}
public static void Warning(this INotifier notifier, string text)
{
notifier.AddMessage(MessageType.warning, text);
}
//This is the method that takes care of using it directly on your view
//You'll use it like @Html.ViewContext.DisplayMessages()
public static MvcHtmlString DisplayMessages(this ViewContext context)
{
if (!context.Controller.TempData.ContainsKey(ConstKeys.TempDataKey))
{
return null;
}
var messages = (IEnumerable<MessageSystem>)context.Controller.TempData[ConstKeys.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());
}
}
第四。实现ActionFilter,它将负责获取将保存您的消息的全局TempData:
/**
* public class NotifierFilterAttribute : IActionFilter
* */
public class NotifierFilterAttribute : IActionFilter
{
private INotifier Notifier;
/**
* This is the tricky part. We can't do constructor injections automatically on Action Filters.
* Microsoft has taken notice and fixed this issue in MVC 6. What we are going to do
* in here is that we will use Ninject to inject this whole class to the filter pipeline instead
* of using the built-in way of MVC 5. With that possibility Ninject will be able to inject the
* INotifier object successfully.
* */
public NotifierFilterAttribute(INotifier Notifier)
{
this.Notifier = Notifier;
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
var messages = Notifier.Messages;
if(messages.Any())
{
filterContext.Controller.TempData[ConstKeys.TempDataKey] = messages;
}
}
//We will not be using this. But since this is an interface we need to implement it.
//We will leave it blank since we will not be using it.
public void OnActionExecuting(ActionExecutingContext filterContext) { }
}
如上面的注释所述,通过MVC调用的Action Filters不支持自动构造函数注入。
不用担心,我们差不多完成了!
在你的解决方案中,你必须为Ninject定义一个RegisterService()方法,它应该如下所示:
private static void RegisterServices(IKernel kernel)
第五。 在该方法内添加以下内容:
private static void RegisterServices(IKernel kernel)
{
//Your original code unmodified. Omitted for convenience
//This is the messaging system.
kernel.BindFilter<NotifierFilterAttribute>(FilterScope.Controller, 0);
}
在上面的上一段代码中,我们告诉Ninject注入NotifierFilterAttribute EVERYWHERE 。如果要在特定控制器上添加类,则必须在(FIlterScope.Controller,0)之后添加.When子句。这超出了本教程的范围,因此我不会在此处包含它。
请注意,要使BindFilter正常工作,您必须具有以下对文件的引用:
using Ninject.Web.Mvc.FilterBindingSyntax;
就我而言,Visual Studio没有自动解决依赖关系。这就是我在这里展示它的原因。
第六。查看您正在放置Ninject绑定的解决方案。
他们通常采用以下方法:
private void AddBindings()
在其中,添加以下代码行:
kernel.Bind<INotifier>().To<Notifier>().InRequestScope();
如上所述,请使用以下内容使InRequestScope正常工作,因为VS无法识别它。
using Ninject.Web.Common;
Ninject将自动创建Notifier对象并将其插入到调用INotifier的任何位置。我们添加InRequestScope()因为我们需要在整个应用程序中实例化SAME对象。否则它将无法工作,您将在Action Filter上收到一个空的Notifier对象。
第七。随处使用!
public class ArticleController : Controller
{
readonly INotifier notifier;
public ArticleController(INotifier notifier)
{
this.notifier = notifier;
}
// GET: Content
public ActionResult Index()
{
notifier.Success("Yahoo!");
return View();
}
}
第8个最后部分:放置要阅读的消息。如果您希望它们出现在每个页面上,请在_Layout.cshtml文件中添加以下行:
@Html.ViewContext.DisplayMessages()
输出的HTML来自MessageSystem类的Generate()方法,以防您需要进行一些修改。
就是这样!
我很遗憾这么啰嗦。我只想尽可能清楚。
原始问题的来源:
http://forums.asp.net/p/2062006/5957330.aspx?p=True&t=635762674289334403