我们有一个连接到数据库的 WCF REST 服务。事实上,我们有几个数据库实例,都具有相同的模式。
我们想为每个数据库实例设置一个端点,并将连接字符串与端点相关联。该服务将读取连接字符串并连接到适当的 SQL Server 实例。
我确信这是可能的;这是个好主意吗?我该如何设置?MSDN上有文档吗?
编辑:我找到了这个问题,答案建议在标题中添加客户端的连接信息。我不想这样做——出于安全原因,并且因为我确实希望每个数据库都有一个不同的 uri。
我们有一个连接到数据库的 WCF REST 服务。事实上,我们有几个数据库实例,都具有相同的模式。
我们想为每个数据库实例设置一个端点,并将连接字符串与端点相关联。该服务将读取连接字符串并连接到适当的 SQL Server 实例。
我确信这是可能的;这是个好主意吗?我该如何设置?MSDN上有文档吗?
编辑:我找到了这个问题,答案建议在标题中添加客户端的连接信息。我不想这样做——出于安全原因,并且因为我确实希望每个数据库都有一个不同的 uri。
这比我想象的要难一些。WCF 有很多可扩展点,很难选择合适的。如果您认为有更好的方法或有任何问题,请回答或评论。
我已经决定使用实现IEndpointBehavior和IDispatchMessageInspector的自定义类。我有一个派生自BehaviorExtensionElement的类,它允许我将行为与配置中的端点相关联。 这篇博文描述了热门的做法。
我的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>
/// Returns the connection string to use for this service call.
/// </summary>
/// <returns>A SQL Server database connection string.</returns>
private string GetConnectionString()
{
string connectionStringName = (string)OperationContext.Current.IncomingMessageProperties["connectionStringName"];
return ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
}
我的BehaviorExtensionElement
课看起来像这样:
/// <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);
}
}
我的 web.config 包含如下内容:
<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>
节中的每个<endpoint />
元素都将<services />
其behaviorConfiguration
设置为节中适当元素的名称<endpointBehaviors />
。
为什么不添加一个新参数来指定调用将连接的数据库是什么?
例如:
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;
}
取自MSDN
private string getConnectionStringForDb(int type)
{
System.Configuration.ConnectionStringSettings connString;
System.Configuration.Configuration rootWebConfig = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/MyWebSiteRoot");
if (rootWebConfig.ConnectionStrings.ConnectionStrings.Count > 0) {
connString = rootWebConfig.ConnectionStrings.ConnectionStrings["DBConnectionString_" + type];
if (connString == null) {
// LOG ERROR
}
}
return connString.ConnectionString;
}
只需在您的和名称中添加您的连接字符串,web.config
然后像:
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>
...
您可以通过这种方式在运行时检索值:
private static string GetConfigValue()
{
ServiceEndpointCollection ec = OperationContext.Current
.Host.Description.Endpoints;
if (ec!=null)
{
var segments = ec[0].Address.ToString().Split('/');
var s = segments[segments.Length-1]; // "Foo.svc"
return ConfigurationManager.AppSettings[s]; // "tagvalue1"
}
return null;
}