C# C中泛型类型到配置值的映射#

C# C中泛型类型到配置值的映射#,c#,.net,generics,C#,.net,Generics,我有一个用于保存web服务访问的连接配置信息的界面: public interface IServiceConnectionConfiguration { string Username { get; } string Password { get; } string ChannelEndpointUrl { get; } string MediaEndpointUrl { get; } string PlayerlEndpointUrl { get; }

我有一个用于保存web服务访问的连接配置信息的界面:

public interface IServiceConnectionConfiguration
{
    string Username { get; }
    string Password { get; }
    string ChannelEndpointUrl { get; }
    string MediaEndpointUrl { get; }
    string PlayerlEndpointUrl { get; }
    string PlaylistEndpointUrl { get; }
}
我有一个工厂类,它返回特定于所请求服务类型的服务实例

public static class ServiceClientFactory
{
    public static void Configure(IServiceConnectionConfiguration config)
    {
        _config = config;
    }
    public static T GetService<T>() where T : class, IServiceClient
    {
    }
}
公共静态类ServiceClientFactory
{
公共静态无效配置(IServiceConnectionConfiguration配置)
{
_config=config;
}
公共静态T GetService(),其中T:class,IServiceClient
{
}
}
这家工厂被称为

Channel channelService   = factory.GetService<Channel>();
channelService=factory.GetService();
我想弄明白的是,对于工厂代码来说,根据初始化期间传递的配置对象,解析传入类型本身的端点URL是一种优雅的方式。例如,如果传递的类型参数是channel,则在构造ChannelService时,它应该采用ChannelEndpointUrl

我曾考虑过使用config类上的属性用端点URL对应的服务类型来修饰端点URL,但这似乎是一个糟糕的设计


任何想法。

好吧,一种方法是让工厂有一个包含初始化逻辑的私有静态字典,按“类型”索引。类似于战略模式

例如:

public static class ServiceClientFactory
{
    private static IServiceConnectionConfiguration _config;
    private static readonly Dictionary<Type, Func<IServiceClient>> Initializers = new Dictionary<Type, Func<IServiceClient>>();

    static ServiceClientFactory()
    {
        Initializers.Add(typeof(Channel), () =>
                                               {
                                                   return //create the service client based on the endpoint
                                               });
    }

    public static void Configure(IServiceConnectionConfiguration config)
    {
        _config = config;
    }

    public static T GetService<T>() where T : class, IServiceClient
    {
        return (T)Initializers[typeof (T)]();
    }
}
公共静态类ServiceClientFactory
{
专用静态IServiceConnectionConfiguration\u config;
私有静态只读字典初始值设定项=new Dictionary();
静态ServiceClientFactory()
{
初始值设定项。添加(频道的类型),()=>
{
return//基于端点创建服务客户端
});
}
公共静态无效配置(IServiceConnectionConfiguration配置)
{
_config=config;
}
公共静态T GetService(),其中T:class,IServiceClient
{
返回(T)初始值设定项[类型(T)]();
}
}
编辑:现在,正如您所提到的,您无法在工厂中显式实例化,因为这会导致循环引用,您可以强制使用一个新的()约束,并在GetService方法中构造实例,并且只使用字典进行端点配置,例如:

public static class ServiceClientFactory
{
    private static IServiceConnectionConfiguration _config;
    private static readonly Dictionary<Type, Action<IServiceClient>> Initializers = new Dictionary<Type, Action<IServiceClient>>();

    static ServiceClientFactory()
    {
        Initializers.Add(typeof(Channel), t =>
                                              {
                                                  t.Url = _config.ChannelEndpointUrl;
                                                  //configure t using the appropriate endpoint
                                              });
    }

    public static void Configure(IServiceConnectionConfiguration config)
    {
        _config = config;
    }

    public static T GetService<T>() where T : class, IServiceClient, new()
    {
        var service = new T();
        Initializers[typeof(T)](service);
        return service;
    }
}
公共静态类ServiceClientFactory
{
专用静态IServiceConnectionConfiguration\u config;
私有静态只读字典初始值设定项=new Dictionary();
静态ServiceClientFactory()
{
初始值设定项.Add(typeof(Channel),t=>
{
t、 Url=_config.ChannelEndpointUrl;
//使用适当的端点配置t
});
}
公共静态无效配置(IServiceConnectionConfiguration配置)
{
_config=config;
}
公共静态T GetService(),其中T:class,IServiceClient,new()
{
var服务=新的T();
初始设定人[类型(T)](服务);
回程服务;
}
}

A旁注:您应该使用而不是System.String来存储密码。SecureString在内存中保持加密,因此在程序崩溃和内存转储等情况下,它可以更好地保护密码。@Adam SecureString可以被多种工具破坏,坦率地说,这是一个需要处理的问题。它有用途,但第一个问题应该是“我保护它的目的是什么?这个密码是从哪里来的?”-在许多情况下,使用SecureString可能毫无意义。在配置文件中存储密码的最佳方式是什么。然后可能是我可以在应用程序中使用安全字符串。@snkar如果密码以明文形式存储,使用安全字符串不会对您有任何好处,因为攻击者会先搜索配置文件,然后再搜索程序内存的内容。即使密码已加密,攻击者也可能复制程序的解密逻辑,并绕过程序的内存。一般来说,确保密码安全的最佳方法是让操作系统和.NET框架管理密码。例如,可以使用当前登录用户的凭据连接到SQL Server,这就解决了这个问题。@MarcGravel 100%同意。但是这个问题并没有说明如何对攻击者建模,所以很难判断SecureString在这里是否合适。如果密码存储在配置文件中,那么正如我在上面的评论中所说的,SecureString几乎毫无意义。问题是我无法在工厂中引用服务实现类,因为这样我将遇到循环引用问题。工厂应根据传递给GetService调用的类型参数解析服务类运行时。我刚刚在上面进行了编辑,以提供一个替代实现,该实现基于new()约束创建实例,并仅将字典用于配置目的。我想我以前不清楚。问题在于行:Initializers.Add(typeof(Channel)…我无法在工厂中引用通道类,因为这会导致循环引用问题。现在,如果您真正需要为每个通道类做的只是设置Url,那么您可能可以将其简化很多,例如,不必使用配置的操作字典,只需使用返回Url的Func字典,如h as:()=>\u config.channelEndpointUrl我明白了……那么,在这种情况下,让IServiceClient声明一个无效配置(IServiceConnectionConfiguration config)会不会更简洁呢,并让每个服务采用适合它的设置?同时忽略字典。如果不知道类型本身,则不能有特定的行为。