我有一个使用c#和ASP.NET MVC 5编写的应用程序。我也使用Unity.Mvc进行依赖注入。
与许多其他类一起,类Windows calls
已在MessageManager
容器中注册。但是,IoC
类依赖于MessageManager
的实例来执行其工作。该类用于为视图编写临时数据。
为了解析TempDataDictionary
的实例,我还需要注册MessageManager
的实例。我需要能够从TempDataDictionary
类向TempDataDictionary
添加值,然后我需要从视图中访问临时数据。因此,我需要能够在视图中访问同一个MessageManager
实例,以便我可以将消息写出来给用户。
此外,如果控制器将用户重定向到其他地方,我不想丢失该消息,我仍然希望能够在下一个视图中显示该消息。
我尝试了以下操作来注册TempDataDictionary
和TempDataDictionary
:
MessageManager
然后在我看来,我有以下内容要解析为Container.RegisterType<TempDataDictionary>(new PerThreadLifetimeManager())
.RegisterType<IMessageManager, MessageManager>();
IMessageManager
然而,由于某种原因,消息会丢失。也就是说,当我解析var manager = DependencyResolver.Current.GetService<IMessageManager>();
时,manager
不包含TempDataDictionary
从控制器添加的任何消息。
如何才能正确注册MessageManager
的实例,以便数据在查看之前一直存在?
已更新
这是我的TempDataDictionary
界面
IMessageManager
答案 0 :(得分:6)
TempDataDictionary
是MessageManager
实现的固有部分,因此,您应该直接在该类中实现它,而不是将其注册到容器中。
类似的东西:
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
}
然后,您可以跨请求保留此消息,管理何时将消息标记为已显示,甚至让用户查看其旧消息(如果您愿意)