如何正确地将 `TempDataDictionary` 注入我的 类?
How can I correctly inject `TempDataDictionary` into my classes?
我有一个使用 c# 和 ASP.NET MVC 5 编写的应用程序。我还使用 Unity.Mvc 进行依赖注入。
与许多其他 classes 一起,class MessageManager
在 IoC
容器中注册。但是,MessageManager
class 依赖于 TempDataDictionary
的实例来执行其工作。此 class 用于为视图写入临时数据。
为了解析 MessageManager
的实例,我还需要注册 TempDataDictionary
的实例。我需要能够从 MessageManager
class 向 TempDataDictionary
添加值,然后我需要从视图访问临时数据。因此,我需要能够在视图中访问 TempDataDictionary
的相同实例,以便我可以将消息写给用户。
此外,如果控制器将用户重定向到别处,我不想丢失消息,我仍然希望能够在下一个视图中显示消息。
我尝试了以下方法来注册 TempDataDictionary
和 MessageManager
:
Container.RegisterType<TempDataDictionary>(new PerThreadLifetimeManager())
.RegisterType<IMessageManager, MessageManager>();
然后在我看来,我有以下内容可以解析为 IMessageManager
的实例
var manager = DependencyResolver.Current.GetService<IMessageManager>();
但是,由于某种原因,消息丢失了。也就是说,当我解析 manager
时,TempDataDictionary
不包含 MessageManager
从控制器添加的任何消息。
如何正确注册 TempDataDictionary
的实例,以便数据在被查看之前一直存在?
已更新
这是我的 IMessageManager
界面
public interface IMessageManager
{
void AddSuccess(string message, int? dismissAfter = null);
void AddError(string message, int? dismissAfter = null);
void AddInfo(string message, int? dismissAfter = null);
void AddWarning(string message, int? dismissAfter = null);
Dictionary<string, IEnumerable<FlashMessage>> GetAlerts();
}
TempDataDictionary
是 MessageManager
实现的固有部分,因此,您应该直接在 class 中实现它,而不是在容器中注册它。
类似于:
public class MessageManager : IMessageManager
{
private TempDataDictionary _tempDataDictionary;
[...]
}
但是,恕我直言,我认为在控制器上下文之外使用 TempDataDictionary
不是一个好习惯,因此与其在 class 中实现它,不如每次都传递它添加或检索消息:
void AddSuccess(IDictionary<string, object> tempData, string message);
您还可以使用 PerThreadLifetimeManager
为每个请求创建一个 MessageManager
实例,然后您根本不需要使用 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
每个会话解析上述 class 实例的实现,例如:
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
这不是严格意义上的答案,而是一个备选建议:
Also, if the controller redirects the user elsewhere, I don't want to lose the message, I still want to be able to show the message on the next view.
仅看上面的内容,我就觉得将消息存储在数据库中可能是更好的选择。这样,您甚至可以回到过去并根据需要查看旧消息。
// persist in EF db context
class Message {
DateTime CreatedUtc { get; set; }
DateTime SeenUtc { get; set; }
string Text { get; set; }
AspNetUser User { get; set; }
// etc
}
然后您可以跨请求保留此消息,管理何时将消息标记为已读,甚至让用户查看他的旧消息(如果您愿意的话)
我有一个使用 c# 和 ASP.NET MVC 5 编写的应用程序。我还使用 Unity.Mvc 进行依赖注入。
与许多其他 classes 一起,class MessageManager
在 IoC
容器中注册。但是,MessageManager
class 依赖于 TempDataDictionary
的实例来执行其工作。此 class 用于为视图写入临时数据。
为了解析 MessageManager
的实例,我还需要注册 TempDataDictionary
的实例。我需要能够从 MessageManager
class 向 TempDataDictionary
添加值,然后我需要从视图访问临时数据。因此,我需要能够在视图中访问 TempDataDictionary
的相同实例,以便我可以将消息写给用户。
此外,如果控制器将用户重定向到别处,我不想丢失消息,我仍然希望能够在下一个视图中显示消息。
我尝试了以下方法来注册 TempDataDictionary
和 MessageManager
:
Container.RegisterType<TempDataDictionary>(new PerThreadLifetimeManager())
.RegisterType<IMessageManager, MessageManager>();
然后在我看来,我有以下内容可以解析为 IMessageManager
var manager = DependencyResolver.Current.GetService<IMessageManager>();
但是,由于某种原因,消息丢失了。也就是说,当我解析 manager
时,TempDataDictionary
不包含 MessageManager
从控制器添加的任何消息。
如何正确注册 TempDataDictionary
的实例,以便数据在被查看之前一直存在?
已更新
这是我的 IMessageManager
界面
public interface IMessageManager
{
void AddSuccess(string message, int? dismissAfter = null);
void AddError(string message, int? dismissAfter = null);
void AddInfo(string message, int? dismissAfter = null);
void AddWarning(string message, int? dismissAfter = null);
Dictionary<string, IEnumerable<FlashMessage>> GetAlerts();
}
TempDataDictionary
是 MessageManager
实现的固有部分,因此,您应该直接在 class 中实现它,而不是在容器中注册它。
类似于:
public class MessageManager : IMessageManager
{
private TempDataDictionary _tempDataDictionary;
[...]
}
但是,恕我直言,我认为在控制器上下文之外使用 TempDataDictionary
不是一个好习惯,因此与其在 class 中实现它,不如每次都传递它添加或检索消息:
void AddSuccess(IDictionary<string, object> tempData, string message);
您还可以使用 PerThreadLifetimeManager
为每个请求创建一个 MessageManager
实例,然后您根本不需要使用 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
每个会话解析上述 class 实例的实现,例如:
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
这不是严格意义上的答案,而是一个备选建议:
Also, if the controller redirects the user elsewhere, I don't want to lose the message, I still want to be able to show the message on the next view.
仅看上面的内容,我就觉得将消息存储在数据库中可能是更好的选择。这样,您甚至可以回到过去并根据需要查看旧消息。
// persist in EF db context
class Message {
DateTime CreatedUtc { get; set; }
DateTime SeenUtc { get; set; }
string Text { get; set; }
AspNetUser User { get; set; }
// etc
}
然后您可以跨请求保留此消息,管理何时将消息标记为已读,甚至让用户查看他的旧消息(如果您愿意的话)