我可以将连接字符串与WCF中的端点相关联吗?

我可以将连接字符串与WCF中的端点相关联吗?,wcf,web-services,rest,.net-4.0,web-config,Wcf,Web Services,Rest,.net 4.0,Web Config,我们有一个连接到数据库的WCF REST服务。事实上,我们有多个数据库实例,都具有相同的模式 我们希望为每个数据库实例设置一个端点,并将连接字符串与端点关联。该服务将读取连接字符串并连接到相应的SQL Server实例 我相信这是可能的;这是个好主意吗?我如何设置它?有关于MSDN的文档吗 编辑:我找到了,答案建议在标题中添加客户端的连接信息。出于安全考虑,我不想这样做,因为我确实希望每个数据库都有一个不同的uri。为什么不添加一个新参数,指定调用将连接的数据库是什么 例如: 您可以添加一个d

我们有一个连接到数据库的WCF REST服务。事实上,我们有多个数据库实例,都具有相同的模式

我们希望为每个数据库实例设置一个端点,并将连接字符串与端点关联。该服务将读取连接字符串并连接到相应的SQL Server实例

我相信这是可能的;这是个好主意吗?我如何设置它?有关于MSDN的文档吗


编辑:我找到了,答案建议在标题中添加客户端的连接信息。出于安全考虑,我不想这样做,因为我确实希望每个数据库都有一个不同的uri。

为什么不添加一个新参数,指定调用将连接的数据库是什么

例如:

  • 您可以添加一个
    db
    参数,该参数将获得一个数字,然后从那里连接
  • 您可以在身份验证方法上添加此类参数
作为第一项的示例:

public ProductItem GetProduct(int productId, int db = 1)
{
    ProductItem product = new ProductItem();
    string connectionString = getConnectionStringForDb(db);

    using (SqlConnection connection =
        new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand("SELECT name, price FROM Products WHERE productId = @product;", connection);
        command.Parameters.AddWithValue("@product", productId);

        try
        {
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            reader.Read();

            product = new product({
                Name = reader[0],
                Price = reader[1]
            });

            reader.Close();
        }
        catch (Exception ex)
        {
            // Log exception
        }
    }

    return product;
}
采取

只需将您的连接字符串添加到
web.config
和name中,然后如下所示:

DBConnectionString_1, DBConnectionString_2, DBConnectionString_3
或者任何对你有意义的事情

<connectionStrings>
  <add 
    name="DBConnectionString_1" 
    connectionString="Data Source=serverName;Initial 
    Catalog=Northwind;Persist Security Info=True;User 
    ID=userName;Password=password"
    providerName="System.Data.SqlClient"
  />
  <add 
    name="DBConnectionString_2" 
    connectionString="Data Source=serverName;Initial 
    Catalog=Northwind;Persist Security Info=True;User 
    ID=userName;Password=password"
    providerName="System.Data.SqlClient"
  />
  <add 
    name="DBConnectionString_3" 
    connectionString="Data Source=serverName;Initial 
    Catalog=Northwind;Persist Security Info=True;User 
    ID=userName;Password=password"
    providerName="System.Data.SqlClient"
  />
</connectionStrings>

在web.config中使用此选项:

<configuration>

  <appSettings>
    <add key="Foo.svc" value="tagvalue1"/>
  </appSettings>
  ...

这比我想象的要难一些。WCF有很多扩展点,很难选择正确的扩展点。请回答或评论,如果你认为有更好的方法,或与此有关的任何错误

我已经决定使用一个实现和的自定义类。我有一个派生自的类,它允许我将行为与配置中的端点相关联。你可以这样做

我的
DatabaseConnectionContext
类如下所示:

/// <summary>
/// An endpoint behavior that associates a database connection string name with the endpoint and adds it to the
/// properties of incoming messages.
/// </summary>
public class DatabaseConnectionContext : IEndpointBehavior, IDispatchMessageInspector
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DatabaseConnectionContext"/> class with the provided connection string name.
    /// </summary>
    /// <param name="connectionStringName">The name of the connection string to associate with the endpoint.</param>
    public DatabaseConnectionContext(string connectionStringName)
    {
        this.ConnectionStringName = connectionStringName;
    }

    /// <summary>
    /// Gets the name of the connection string to associate with the endpoint.
    /// </summary>
    public string ConnectionStringName { get; private set; }

    /// <inheritdoc />
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    /// <inheritdoc />
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        throw new NotImplementedException();
    }

    /// <inheritdoc />
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
    }

    /// <inheritdoc />
    public void Validate(ServiceEndpoint endpoint)
    {
    }

    /// <inheritdoc />
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        request.Properties["connectionStringName"] = this.ConnectionStringName;
        return null;
    }

    /// <inheritdoc />
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
    }
}
/// <summary>
/// Associates a <see cref="DatabaseConnectionContext"/> with an endpoint in configuration.
/// </summary>
public class DatabaseConnectionContextBehaviorExtension : BehaviorExtensionElement
{
    /// <summary>
    /// The name of the <see cref="ConnectionStringName"/> property when it appears in a configuration file.
    /// </summary>
    private const string ConnectionStringNamePropertyName = "connectionStringName";

    /// <summary>
    /// Gets or sets the name of the configuration string to associate with the endpoint.
    /// </summary>
    [ConfigurationProperty(ConnectionStringNamePropertyName)]
    public string ConnectionStringName
    {
        get
        {
            return (string)this[ConnectionStringNamePropertyName];
        }

        set
        {
            this[ConnectionStringNamePropertyName] = value;
        }
    }

    /// <inheritdoc />
    public override Type BehaviorType
    {
        get { return typeof(DatabaseConnectionContext); }
    }

    /// <inheritdoc />
    protected override object CreateBehavior()
    {
        return new DatabaseConnectionContext(this.ConnectionStringName);
    }
}
<behaviors>

  <endpointBehaviors>
    <behavior name="DevRestEndpointConfiguration">
      <webHttp helpEnabled="false" />
      <connectionStringInterceptor connectionStringName="myDevConnectionStringName" />
    </behavior>
    <behavior name="ProductionRestEndpointConfiguration">
      <webHttp helpEnabled="false" />
      <connectionStringInterceptor connectionStringName="myProductionConnectionStringName" />
    </behavior>
  </endpointBehaviors>

</behaviors>

<extensions>
  <behaviorExtensions>
    <add name="connectionStringInterceptor" type="DatabaseConnectionContextBehaviorExtension, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
My web.config包含如下内容:

/// <summary>
/// An endpoint behavior that associates a database connection string name with the endpoint and adds it to the
/// properties of incoming messages.
/// </summary>
public class DatabaseConnectionContext : IEndpointBehavior, IDispatchMessageInspector
{
    /// <summary>
    /// Initializes a new instance of the <see cref="DatabaseConnectionContext"/> class with the provided connection string name.
    /// </summary>
    /// <param name="connectionStringName">The name of the connection string to associate with the endpoint.</param>
    public DatabaseConnectionContext(string connectionStringName)
    {
        this.ConnectionStringName = connectionStringName;
    }

    /// <summary>
    /// Gets the name of the connection string to associate with the endpoint.
    /// </summary>
    public string ConnectionStringName { get; private set; }

    /// <inheritdoc />
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    /// <inheritdoc />
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        throw new NotImplementedException();
    }

    /// <inheritdoc />
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
    }

    /// <inheritdoc />
    public void Validate(ServiceEndpoint endpoint)
    {
    }

    /// <inheritdoc />
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        request.Properties["connectionStringName"] = this.ConnectionStringName;
        return null;
    }

    /// <inheritdoc />
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
    }
}
/// <summary>
/// Associates a <see cref="DatabaseConnectionContext"/> with an endpoint in configuration.
/// </summary>
public class DatabaseConnectionContextBehaviorExtension : BehaviorExtensionElement
{
    /// <summary>
    /// The name of the <see cref="ConnectionStringName"/> property when it appears in a configuration file.
    /// </summary>
    private const string ConnectionStringNamePropertyName = "connectionStringName";

    /// <summary>
    /// Gets or sets the name of the configuration string to associate with the endpoint.
    /// </summary>
    [ConfigurationProperty(ConnectionStringNamePropertyName)]
    public string ConnectionStringName
    {
        get
        {
            return (string)this[ConnectionStringNamePropertyName];
        }

        set
        {
            this[ConnectionStringNamePropertyName] = value;
        }
    }

    /// <inheritdoc />
    public override Type BehaviorType
    {
        get { return typeof(DatabaseConnectionContext); }
    }

    /// <inheritdoc />
    protected override object CreateBehavior()
    {
        return new DatabaseConnectionContext(this.ConnectionStringName);
    }
}
<behaviors>

  <endpointBehaviors>
    <behavior name="DevRestEndpointConfiguration">
      <webHttp helpEnabled="false" />
      <connectionStringInterceptor connectionStringName="myDevConnectionStringName" />
    </behavior>
    <behavior name="ProductionRestEndpointConfiguration">
      <webHttp helpEnabled="false" />
      <connectionStringInterceptor connectionStringName="myProductionConnectionStringName" />
    </behavior>
  </endpointBehaviors>

</behaviors>

<extensions>
  <behaviorExtensions>
    <add name="connectionStringInterceptor" type="DatabaseConnectionContextBehaviorExtension, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>


部分中的每个
元素都将其
行为配置设置为
部分中相应元素的名称。

我非常喜欢这个建议。它适用于REST服务,其中URI的一部分可以很容易地作为参数传递给服务方法。然而,我使用了另一种解决方案,请参阅我自己的回复,因为我认为如果我们稍后公开SOAP端点,它会工作得更好。此外,我们不一定希望web.config中显示的每个连接字符串都可用。