如何在 WCF 服务方法调用之间保留值?
How can I preserve values between WCF service methods calling?
我有这个 WCF 服务 class:
public partial class OhmioSVC: IOhmioSVC_Security
{
// Porque no funciona si la variable no es estatica?
private static ConnectionBusiness _conn = new ConnectionBusiness();
public ConnectionBusiness Conn
{
get
{
return _conn;
}
}
public void Connect(string Usuario, string Password, string DataBase)
{
Conn.ObtenerTicket (Usuario, Password, DataBase);
}
public List<Errores> GetErrors()
{
return Conn.MyErrors;
}
}
如您所见,_conn 被定义为静态的,因为我需要在调用之间保留他的值。如果我删除 "static",并调用方法 Connect(创建 _conn 对象)然后调用 getErrores _conn 变量由于某种原因为空。
问题在于,如果我错过调用 "connect" 方法,我想抛出异常,但 _conn 仍然从上次调用中获取值。我知道我在这里做错了什么,但我看不到另一种选择。有什么想法吗?
谢谢
默认情况下,为创建的每个新 session 实例化 WCF 服务 class。对于某些不支持会话的绑定,然后 "session" 仅跨越单个调用,这意味着对于来自客户端的两个调用(一个用于 Connect
,一个用于 GetErrors
),将是创建的 OhmioSVC
class 的两个实例,这就是为什么如果您不将 ConnectionBusiness
属性 指定为静态,将创建其中两个,您将得到你看到的结果。
您需要告诉 WCF 您需要服务合同中的会话。您可以通过在服务合同声明中添加 SessionMode
属性 来做到这一点:
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOhmio_Security
{
[OperationContract]
void Connect(string user, string password, string db);
[OperationContract]
List<string> GetErrors();
}
如果您拥有它,并且您使用了不支持会话的绑定(例如 BasicHttpBinding),那么您的服务将无法打开 - 然后您需要更改为支持会话的绑定(例如 WSHttpBinding) .下面的代码显示了一个会话有效的示例:
public class Whosebug_31541498
{
class ConnectionBusiness
{
List<string> errors = new List<string>();
public void ObtenerTicket(string user, string password, string db)
{
errors.Add(string.Format("ObtenerTicket called: {0}, {1}, {2}", user, password, db));
}
public List<string> MyErrors
{
get
{
var result = new List<string>(this.errors);
errors.Clear();
if (result.Count == 0)
{
result.Add("No errors!");
}
return result;
}
}
}
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOhmio_Security
{
[OperationContract]
void Connect(string user, string password, string db);
[OperationContract]
List<string> GetErrors();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class OhmioSVC : IOhmio_Security
{
private ConnectionBusiness _conn = new ConnectionBusiness();
public void Connect(string user, string password, string db)
{
_conn.ObtenerTicket(user, password, db);
}
public List<string> GetErrors()
{
return _conn.MyErrors;
}
}
static Binding GetBinding()
{
// var result = new BasicHttpBinding(); // This will not work, as it doesn't support sessions
var result = new WSHttpBinding(); // This will work
return result;
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(OhmioSVC), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IOhmio_Security), GetBinding(), "");
host.Open();
Console.WriteLine("Host opened");
var factory = new ChannelFactory<IOhmio_Security>(GetBinding(), new EndpointAddress(baseAddress));
var proxy = factory.CreateChannel();
proxy.Connect("user", "pwd", "db");
var errors = proxy.GetErrors();
Console.WriteLine("Errors:\n {0}", string.Join("\n ", errors));
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
另一种方法是在您的方案中合并这两种方法 - 使 Connect
return 成为错误列表,这样您就不必单独调用来获取它们,而且您不必处理会话。
我有这个 WCF 服务 class:
public partial class OhmioSVC: IOhmioSVC_Security
{
// Porque no funciona si la variable no es estatica?
private static ConnectionBusiness _conn = new ConnectionBusiness();
public ConnectionBusiness Conn
{
get
{
return _conn;
}
}
public void Connect(string Usuario, string Password, string DataBase)
{
Conn.ObtenerTicket (Usuario, Password, DataBase);
}
public List<Errores> GetErrors()
{
return Conn.MyErrors;
}
}
如您所见,_conn 被定义为静态的,因为我需要在调用之间保留他的值。如果我删除 "static",并调用方法 Connect(创建 _conn 对象)然后调用 getErrores _conn 变量由于某种原因为空。
问题在于,如果我错过调用 "connect" 方法,我想抛出异常,但 _conn 仍然从上次调用中获取值。我知道我在这里做错了什么,但我看不到另一种选择。有什么想法吗?
谢谢
默认情况下,为创建的每个新 session 实例化 WCF 服务 class。对于某些不支持会话的绑定,然后 "session" 仅跨越单个调用,这意味着对于来自客户端的两个调用(一个用于 Connect
,一个用于 GetErrors
),将是创建的 OhmioSVC
class 的两个实例,这就是为什么如果您不将 ConnectionBusiness
属性 指定为静态,将创建其中两个,您将得到你看到的结果。
您需要告诉 WCF 您需要服务合同中的会话。您可以通过在服务合同声明中添加 SessionMode
属性 来做到这一点:
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOhmio_Security
{
[OperationContract]
void Connect(string user, string password, string db);
[OperationContract]
List<string> GetErrors();
}
如果您拥有它,并且您使用了不支持会话的绑定(例如 BasicHttpBinding),那么您的服务将无法打开 - 然后您需要更改为支持会话的绑定(例如 WSHttpBinding) .下面的代码显示了一个会话有效的示例:
public class Whosebug_31541498
{
class ConnectionBusiness
{
List<string> errors = new List<string>();
public void ObtenerTicket(string user, string password, string db)
{
errors.Add(string.Format("ObtenerTicket called: {0}, {1}, {2}", user, password, db));
}
public List<string> MyErrors
{
get
{
var result = new List<string>(this.errors);
errors.Clear();
if (result.Count == 0)
{
result.Add("No errors!");
}
return result;
}
}
}
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOhmio_Security
{
[OperationContract]
void Connect(string user, string password, string db);
[OperationContract]
List<string> GetErrors();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class OhmioSVC : IOhmio_Security
{
private ConnectionBusiness _conn = new ConnectionBusiness();
public void Connect(string user, string password, string db)
{
_conn.ObtenerTicket(user, password, db);
}
public List<string> GetErrors()
{
return _conn.MyErrors;
}
}
static Binding GetBinding()
{
// var result = new BasicHttpBinding(); // This will not work, as it doesn't support sessions
var result = new WSHttpBinding(); // This will work
return result;
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(OhmioSVC), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IOhmio_Security), GetBinding(), "");
host.Open();
Console.WriteLine("Host opened");
var factory = new ChannelFactory<IOhmio_Security>(GetBinding(), new EndpointAddress(baseAddress));
var proxy = factory.CreateChannel();
proxy.Connect("user", "pwd", "db");
var errors = proxy.GetErrors();
Console.WriteLine("Errors:\n {0}", string.Join("\n ", errors));
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
另一种方法是在您的方案中合并这两种方法 - 使 Connect
return 成为错误列表,这样您就不必单独调用来获取它们,而且您不必处理会话。