如何使用Ninject 3在MVC 5中创建消息传递系统?

时间:2015-08-27 16:09:11

标签: c# asp.net-mvc

如何使用Ninject 3在MVC 5中实现全局消息传递系统?  我想要实现的目标很简单:

我想添加一条消息,例如:“您已成功完成任务”并将其读入_Layout视图。我会使用ViewBag,ViewData或TempData。问题在于,为了分离问题,我在控制器范围之外做了很多处理逻辑(通过依赖注入)。这意味着ViewBag,ViewData和TempData是不可能的(除非我使用Controller扩展注入的类)

所以我尝试创建一个处理任务的全局静态类。问题是该类向应用程序的所有用户显示,而与其身份验证无关。

1 个答案:

答案 0 :(得分:2)

大部分功劳都来自asp.net论坛和他的帖子Send Success Message to View using TempData

您可以在上面的链接中查看他的帖子。代码主要是相同的,我只是修剪了一些我不需要的功能,最后,我使用的是Ninject而不是Autofac(这是使用的IoC容器级别)

<强>目的: 当使用Ninject 3作为IoC容器时,您希望使用ASP.NET MVC 5实现全局消息传递系统。

在开始之前,我将假设以下内容:

  1. 您安装了ASP.NET MVC 3或更高版本
  2. 您正在使用Ninject 3
  3. 您已经配置了Ninject并且对它有一点了解。
  4. 我已经让你知道基本的关注点分离,并根据一个好的判断来划分类和文件。
  5. 虽然不是强制性的,但我在这种情况下使用Bootstrap进行HTML格式化。
  6. <强>解决方案:

    第一。在解决方案上创建一个新文件并将其命名为“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

相关问题