如何正确地将“TempDataDictionary”注入我的类?

时间:2018-04-30 20:01:46

标签: c# asp.net-mvc asp.net-mvc-5 unity-container

我有一个使用c#和ASP.NET MVC 5编写的应用程序。我也使用Unity.Mvc进行依赖注入。

与许多其他类一起,类Windows calls已在MessageManager容器中注册。但是,IoC类依赖于MessageManager的实例来执行其工作。该类用于为视图编写临时数据。

为了解析TempDataDictionary的实例,我还需要注册MessageManager的实例。我需要能够从TempDataDictionary类向TempDataDictionary添加值,然后我需要从视图中访问临时数据。因此,我需要能够在视图中访问同一个MessageManager实例,以便我可以将消息写出来给用户。

此外,如果控制器将用户重定向到其他地方,我不想丢失该消息,我仍然希望能够在下一个视图中显示该消息。

我尝试了以下操作来注册TempDataDictionaryTempDataDictionary

MessageManager

然后在我看来,我有以下内容要解析为Container.RegisterType<TempDataDictionary>(new PerThreadLifetimeManager()) .RegisterType<IMessageManager, MessageManager>();

的实例
IMessageManager

然而,由于某种原因,消息会丢失。也就是说,当我解析var manager = DependencyResolver.Current.GetService<IMessageManager>(); 时,manager不包含TempDataDictionary从控制器添加的任何消息。

如何才能正确注册MessageManager的实例,以便数据在查看之前一直存在?

已更新 这是我的TempDataDictionary界面

IMessageManager

2 个答案:

答案 0 :(得分:6)

TempDataDictionaryMessageManager实现的固有部分,因此,您应该直接在该类中实现它,而不是将其注册到容器中。

类似的东西:

public class MessageManager : IMessageManager
{
    private TempDataDictionary _tempDataDictionary;

    [...]
}

然而,恕我直言,我不认为从控制器上下文中使用TempDataDictionary是一个好习惯,所以不是在你的类中实现它,你可以在每次添加或检索消息时传递它:

void AddSuccess(IDictionary<string, object> tempData, string message);

您还可以使用MessageManager为每个请求创建一个PerThreadLifetimeManager实例,然后您根本不需要使用TempDataDictionary,您可以使用常规列表自行实现或词典:

public class MessageManager : IMessageManager
{
    private List<string> _successMessages = new List<string>();
    private List<string> _errorMessages = new List<string>();
    private List<string> _warningMessage = new List<string>();
    private List<string> _infoMessage = new List<string>();

    public void AddSuccess(string message)
    {
        _successMessages.Add(message);
    }

    public void AddError(string message)
    {
        _errorMessages.Add(message);
    }

    public void AddWarning(string message)
    {
        _warningMessages.Add(message);
    }

    public void AddInfo(string message)
    {
        _infoMessages.Add(message);
    }

    public List<string> SuccessMessages
    {
        get { return _successMessages; }
    }

    public List<string> ErrorMessages
    {
        get { return _errorMessages; }
    }

    public List<string> WarningMessages
    {
        get { return _warningMessages; }
    }

    public List<string> InfoMessages
    {
        get { return _infoMessages; }
    }
}

然后,按线程注册它,以便在每个请求中清除所有内容:

Container.RegisterType.RegisterType<IMessageManager, MessageManager>
        (new PerThreadLifetimeManager());

更好的方法?

如果要确保列表一直保留到读取之前,即使它在另一个请求中发生,或者您正在使用异步操作或ajax请求,也可以创建自己的LifetimeManager实现每个会话解析上述类的实例,例如:

public class SessionLifetimeManager : LifetimeManager
{
    private string _key = Guid.NewGuid().ToString();
    public override void RemoveValue(ILifetimeContainer container = null)
    {
        HttpContext.Current.Session.Remove(_key);
    }
    public override void SetValue(object newValue, ILifetimeContainer container = null)
    {
        HttpContext.Current.Session[_key] = newValue;
    }
    public override object GetValue(ILifetimeContainer container = null)
    {
        return HttpContext.Current.Session[_key];
    }
    protected override LifetimeManager OnCreateLifetimeManager()
    {
        return new PerSessionLifetimeManager();
    }
}

然后将PerThreadLifetimeManager替换为上面的SessionLifetimeManager,并在每次访问时清除列表,例如:

public List<string> InfoMessages
{
    get 
    { 
         // Some view has accessed the data, clear the list before returning
         var tempInfoMessages = new List<string>(_infoMessages);
         _infoMessages.Clear();
         return tempInfoMessages; 
    }
}

参考:

SessionLifetimeManager来自这里:https://gist.github.com/CrestApps/a246530e386b95d0a05d36bb13805259

答案 1 :(得分:2)

这不是一个严格的答案,而是另一种建议:

  

此外,如果控制器将用户重定向到其他地方,我不想丢失该消息,我仍然希望能够在下一个视图中显示该消息。

只是看上面的内容向我建议,将您的消息存储在数据库中可能是更好的选择。这样,您甚至可以及时回顾并查看旧消息。

// persist in EF db context
class Message {
    DateTime CreatedUtc { get; set; }
    DateTime SeenUtc { get; set; }
    string Text { get; set; }
    AspNetUser User { get; set; }
    // etc
}

然后,您可以跨请求保留此消息,管理何时将消息标记为已显示,甚至让用户查看其旧消息(如果您愿意)