在 Worker 角色中托管 WCF,超时
Host WCF in the Worker Role, Timeout
基本上,我遵循的是:GUIDE
我想要的是使用一个 web 角色 和一个 worker 角色.
将我的 Cloudapp 发布到 azure
辅助角色
我在我的工作者角色中托管一个 WCF 服务,所有 sql 通信都将发生,(DTO 对象)。
网络角色
我的 Web 角色项目只是一个普通的 MVC 应用程序,它具有对 WCF 服务的服务引用。例如,如果用户想要注册,数据将发送到 WCF 服务,然后再发送到数据库。
问题
错误信息:
An exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll but was not handled in user code
Additional information: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
我也遇到超时错误,在此之前我似乎无法再重现了..
我已经非常彻底地遵循了指南。唯一不同的是,我想在一次发布中托管它们,而不是两次。另外,这个人通过点击我没有点击的包来发布项目(我点击发布按钮)。
我完全没有想法。我只找到了两份关于以辅助角色托管 WCF 服务的指南,我现在正在关注的一份和 THIS 一份。两者都非常过时,并没有真正做我想做的事情。两个指南都将 WCF 服务作为独立的 Cloudapp 托管。我想要的是在同一个解决方案中同时发布辅助角色和网络角色,一个 发布。
如果您有任何建议,请在这里留下。我感谢我能得到的所有帮助。非常感谢。
/垂死的程序员
编辑 1 - 代码 -
接口和实现
namespace Fildela_Worker
{
[ServiceContract]
public interface IFildelaService
{
[OperationContract]
void InsertUser(UserDTO user);
}
}
[System.ServiceModel.ServiceBehaviorAttribute(IncludeExceptionDetailInFaults=true)]
public class FildelaService : IFildelaService
{
DataLayer DB = new DataLayer();
public void InsertUser(UserDTO user)
{
User newUser = new User(user.FirstName.ToLower().Trim(), user.LastName.ToLower().Trim(),
user.Email.ToLower().Trim(), user.Password.Trim(), user.PasswordSalt.Trim(), user.AgreeUserAgreement);
DB.User.Add(newUser);
DB.SaveChanges();
}
}
服务定义
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Fildela_Web.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2014-01.2.3">
<WebRole name="Fildela Web" vmsize="Small">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
</WebRole>
<WorkerRole name="Fildela Worker" vmsize="Small">
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<Endpoints>
<InputEndpoint name="port" protocol="tcp" port="9001" />
<InputEndpoint name="mexport" protocol="tcp" port="8001" />
</Endpoints>
</WorkerRole>
</ServiceDefinition>
工人角色开始:
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// Create the host
ServiceHost host = new ServiceHost(typeof(FildelaService));
// Read config parameters
string hostName = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Address.ToString();
int port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Port;
int mexport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["mexport"].IPEndpoint.Port;
// Create Metadata
ServiceMetadataBehavior metadatabehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadatabehavior);
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
string mexendpointurl = string.Format("net.tcp://{0}:{1}/FildelaServiceMetadata", hostName, 8001);
host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexendpointurl, new Uri(mexendpointurl));
// Create end point
string endpointurl = string.Format("net.tcp://{0}:{1}/FildelaService", hostName, 9001);
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), endpointurl, new Uri(endpointurl));
// Open the host
host.Open();
// Trace output
Trace.WriteLine("WCF Listening At: " + endpointurl);
Trace.WriteLine("WCF MetaData Listening At: " + mexendpointurl);
return base.OnStart();
}
MVC WEB.CONFIG:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IFildelaService">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://MYADDRESS.cloudapp.net:9001/FildelaService"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IFildelaService"
contract="FildelaServiceReference.IFildelaService" name="NetTcpBinding_IFildelaService" />
</client>
....
MVC 代理使用:
FildelaServiceClient proxy = new FildelaServiceClient();
UserDTO newUser = new UserDTO()
{
parameters....
};
//Insert user
proxy.InsertAccountOwner(newUser);
编辑 2 - 代码 -
辅助角色
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
StartWCFHost();
return base.OnStart();
}
private void StartWCFHost()
{
var baseaddress = string.Format("net.tcp://{0}/", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["FildelaService"].IPEndpoint);
var host = new ServiceHost(typeof(FildelaService), new Uri(baseaddress));
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), "Database");
host.Open();
}
服务定义
<WorkerRole name="Fildela Worker" vmsize="Small">
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<Endpoints>
<InternalEndpoint name="FildelaService" protocol="tcp" />
</Endpoints>
</WorkerRole>
控制器
private EndpointAddress GetRandomEndpoint()
{
var endpoints = RoleEnvironment.Roles["Fildela Worker"].Instances.Select(i => i.InstanceEndpoints["FildelaService"].IPEndpoint).ToArray();
var r = new Random(DateTime.Now.Millisecond);
return new EndpointAddress(string.Format("net.tcp://{0}/Database", endpoints[r.Next(endpoints.Count() - 1)]));
}
[HttpGet]
[AllowAnonymous]
public ViewResult Contact()
{
var factory = new ChannelFactory<IFildelaService>(new NetTcpBinding(SecurityMode.None));
factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);
var channel = factory.CreateChannel(GetRandomEndpoint());
List<CategoryDTO> contactCategories = channel.GetContactCategories().ToList();
return View(contactCategories);
}
首先,您有合同和服务,要托管您的服务,请删除您添加到 OnStart 方法中的所有代码并添加此方法
private void StartWCFHost()
{
var baseaddress = string.Format("net.tcp://{0}/", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint);
var host = new ServiceHost(typeof(FildelaService), new Uri (baseaddress));
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), "Inserter");
host.Open();
}
也就是说,它只是从您的 OnStart 方法中调用此方法,主机就完成了
现在的问题是关于使用网络服务
在您调用 web 服务时在您的控制器中添加此代码(我们正在创建一个通道工厂,无需添加服务引用)
首先将这个方法添加到你的控制器中
private EndpointAddress GetRandomEndpoint()
{
var endpoints= RoleEnvironment.Roles["PutWorkerRoleName"].Instances.Select(i=>i.InstanceEndpoints["port"].IPEndpoint).ToArray();
var r = new Random(DateTime.Now.Millisecond);
return new EndpointAddress(string.Format("net.tcp://{0}/Inserter", endpoints[r.Next(endpoints.Count() - 1)]));
}
然后添加此代码以在您的控制器方法中调用服务(因为您使用的是 MVC)
var factory = new ChannelFactory<IFildelaService>(new NetTcpBinding(SecurityMode.None));
var channel = factory.CreateChannel(GetRandomEndpoint());
channel.InsertAccountOwner(newUser);
我可能忘记重命名我的工作项目中的一些变量,所以请随时验证您的代码的一致性
更新
我将项目上传到我的 github:
Worker Role WCF host+Web Role
基本上,我遵循的是:GUIDE
我想要的是使用一个 web 角色 和一个 worker 角色.
将我的 Cloudapp 发布到 azure辅助角色
我在我的工作者角色中托管一个 WCF 服务,所有 sql 通信都将发生,(DTO 对象)。
网络角色
我的 Web 角色项目只是一个普通的 MVC 应用程序,它具有对 WCF 服务的服务引用。例如,如果用户想要注册,数据将发送到 WCF 服务,然后再发送到数据库。
问题
错误信息:
An exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll but was not handled in user code
Additional information: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
我也遇到超时错误,在此之前我似乎无法再重现了..
我已经非常彻底地遵循了指南。唯一不同的是,我想在一次发布中托管它们,而不是两次。另外,这个人通过点击我没有点击的包来发布项目(我点击发布按钮)。
我完全没有想法。我只找到了两份关于以辅助角色托管 WCF 服务的指南,我现在正在关注的一份和 THIS 一份。两者都非常过时,并没有真正做我想做的事情。两个指南都将 WCF 服务作为独立的 Cloudapp 托管。我想要的是在同一个解决方案中同时发布辅助角色和网络角色,一个 发布。
如果您有任何建议,请在这里留下。我感谢我能得到的所有帮助。非常感谢。
/垂死的程序员
编辑 1 - 代码 -
接口和实现
namespace Fildela_Worker
{
[ServiceContract]
public interface IFildelaService
{
[OperationContract]
void InsertUser(UserDTO user);
}
}
[System.ServiceModel.ServiceBehaviorAttribute(IncludeExceptionDetailInFaults=true)]
public class FildelaService : IFildelaService
{
DataLayer DB = new DataLayer();
public void InsertUser(UserDTO user)
{
User newUser = new User(user.FirstName.ToLower().Trim(), user.LastName.ToLower().Trim(),
user.Email.ToLower().Trim(), user.Password.Trim(), user.PasswordSalt.Trim(), user.AgreeUserAgreement);
DB.User.Add(newUser);
DB.SaveChanges();
}
}
服务定义
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Fildela_Web.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2014-01.2.3">
<WebRole name="Fildela Web" vmsize="Small">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="Endpoint1" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
</WebRole>
<WorkerRole name="Fildela Worker" vmsize="Small">
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<Endpoints>
<InputEndpoint name="port" protocol="tcp" port="9001" />
<InputEndpoint name="mexport" protocol="tcp" port="8001" />
</Endpoints>
</WorkerRole>
</ServiceDefinition>
工人角色开始:
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// Create the host
ServiceHost host = new ServiceHost(typeof(FildelaService));
// Read config parameters
string hostName = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Address.ToString();
int port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Port;
int mexport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["mexport"].IPEndpoint.Port;
// Create Metadata
ServiceMetadataBehavior metadatabehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadatabehavior);
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
string mexendpointurl = string.Format("net.tcp://{0}:{1}/FildelaServiceMetadata", hostName, 8001);
host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexendpointurl, new Uri(mexendpointurl));
// Create end point
string endpointurl = string.Format("net.tcp://{0}:{1}/FildelaService", hostName, 9001);
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), endpointurl, new Uri(endpointurl));
// Open the host
host.Open();
// Trace output
Trace.WriteLine("WCF Listening At: " + endpointurl);
Trace.WriteLine("WCF MetaData Listening At: " + mexendpointurl);
return base.OnStart();
}
MVC WEB.CONFIG:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IFildelaService">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://MYADDRESS.cloudapp.net:9001/FildelaService"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IFildelaService"
contract="FildelaServiceReference.IFildelaService" name="NetTcpBinding_IFildelaService" />
</client>
....
MVC 代理使用:
FildelaServiceClient proxy = new FildelaServiceClient();
UserDTO newUser = new UserDTO()
{
parameters....
};
//Insert user
proxy.InsertAccountOwner(newUser);
编辑 2 - 代码 -
辅助角色
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
StartWCFHost();
return base.OnStart();
}
private void StartWCFHost()
{
var baseaddress = string.Format("net.tcp://{0}/", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["FildelaService"].IPEndpoint);
var host = new ServiceHost(typeof(FildelaService), new Uri(baseaddress));
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), "Database");
host.Open();
}
服务定义
<WorkerRole name="Fildela Worker" vmsize="Small">
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
<Endpoints>
<InternalEndpoint name="FildelaService" protocol="tcp" />
</Endpoints>
</WorkerRole>
控制器
private EndpointAddress GetRandomEndpoint()
{
var endpoints = RoleEnvironment.Roles["Fildela Worker"].Instances.Select(i => i.InstanceEndpoints["FildelaService"].IPEndpoint).ToArray();
var r = new Random(DateTime.Now.Millisecond);
return new EndpointAddress(string.Format("net.tcp://{0}/Database", endpoints[r.Next(endpoints.Count() - 1)]));
}
[HttpGet]
[AllowAnonymous]
public ViewResult Contact()
{
var factory = new ChannelFactory<IFildelaService>(new NetTcpBinding(SecurityMode.None));
factory.Endpoint.Binding.SendTimeout = new TimeSpan(0, 5, 0);
var channel = factory.CreateChannel(GetRandomEndpoint());
List<CategoryDTO> contactCategories = channel.GetContactCategories().ToList();
return View(contactCategories);
}
首先,您有合同和服务,要托管您的服务,请删除您添加到 OnStart 方法中的所有代码并添加此方法
private void StartWCFHost()
{
var baseaddress = string.Format("net.tcp://{0}/", RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint);
var host = new ServiceHost(typeof(FildelaService), new Uri (baseaddress));
host.AddServiceEndpoint(typeof(IFildelaService), new NetTcpBinding(SecurityMode.None), "Inserter");
host.Open();
}
也就是说,它只是从您的 OnStart 方法中调用此方法,主机就完成了
现在的问题是关于使用网络服务
在您调用 web 服务时在您的控制器中添加此代码(我们正在创建一个通道工厂,无需添加服务引用)
首先将这个方法添加到你的控制器中
private EndpointAddress GetRandomEndpoint()
{
var endpoints= RoleEnvironment.Roles["PutWorkerRoleName"].Instances.Select(i=>i.InstanceEndpoints["port"].IPEndpoint).ToArray();
var r = new Random(DateTime.Now.Millisecond);
return new EndpointAddress(string.Format("net.tcp://{0}/Inserter", endpoints[r.Next(endpoints.Count() - 1)]));
}
然后添加此代码以在您的控制器方法中调用服务(因为您使用的是 MVC)
var factory = new ChannelFactory<IFildelaService>(new NetTcpBinding(SecurityMode.None));
var channel = factory.CreateChannel(GetRandomEndpoint());
channel.InsertAccountOwner(newUser);
我可能忘记重命名我的工作项目中的一些变量,所以请随时验证您的代码的一致性
更新
我将项目上传到我的 github: Worker Role WCF host+Web Role