我目前有一个案例,我有多个客户,他们对他们想要的通知形式(例如电子邮件,传真等)有不同的了解。他们可能还想要一个或多个。因此,我创建了一个具有一些基本反射功能的工厂,该工厂将根据通过客户资料发送的某些参数动态创建具体的类。我很好奇,是否有使用ASP.Net Core依赖注入的更好方法?我在这里输入了工厂代码,以帮助人们了解我正在尝试做的事情。
客户个人资料将以字符串数组的形式发送其已订阅的服务作为CreateInstances的参数,因此将仅动态创建特定的服务。
public Dictionary<string, Type> Notifications;
public NotificationFactory()
{
LoadTypes();
}
public IEnumerable<INotificationService> CreateInstances(params string[] namesOfServices)
{
var servicesToInstantiate = namesOfServices.ToList();
List<INotificationService> result = new List<INotificationService>();
foreach (var service in servicesToInstantiate)
{
Type serviceName = GetServiceNameToCreate(service.ToLower());
if (serviceName != null)
{
result.Add(Activator.CreateInstance(serviceName) as INotificationService);
}
}
return result;
}
private Type GetServiceNameToCreate(string NotificationClassName)
{
return Notifications.FirstOrDefault(a => a.Key.Contains(NotificationClassName)).Value;
}
protected virtual void LoadTypes()
{
Notifications = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => typeof(INotificationService).IsAssignableFrom(t) && !t.IsInterface)
.ToDictionary(t => t.Name.ToLower(), t => t);
}
答案 0 :(得分:0)
采用任意字符串并按照您的方式激活实例是一个坏主意。该字符串至少应列入白名单。例如,如果恶意用户能够篡改数据库中的字符串,则他们可以选择激活哪种类型并可能触发未经授权的行为或拒绝服务。
相反,定义一个白名单,然后将每种类型与构造所需服务的委托相关联。
if (!map.ContainsKey(serviceType)) throw new ArgumentException(nameof(serviceType));
INotificationService service = map[serviceType]();
然后要获得服务,请致电
Func<INotificationService> factory;
if (!map.TryGetValue(serviceType, out factory)) throw new ArgumentException(nameof(serviceType));
INotificationService service = factory();
或者,如果您愿意:
map
通过这种方式,您可以确定服务类型是您所支持的类型,并且不需要使用任何反射。
如果您需要更多扩展性
如果您希望能够添加更多交付方式而无需更改填充{{1}}的代码,则当然可以从配置文件填充地图。尽管我想知道如何在不更改任何代码的情况下实现新的交付方法,以及是否拥有需要您具备能力的真正NFR。在我看来,新的交付方式不会经常添加,而在其他方面也很重要,因此在这里添加一行代码可以节省很多时间。