NLog to WCF. Closing client throws SocketException on Server - wcf

I've been struggling with this problem for a whole day and do not know how to fix it. I have tried various things to resolve the issue but I am at a loss.
I have a project where I am attempting to use the LogReceiverServer from NLog to send and receive messages between 2 PCs. I followed this example here. Everything actually works fine, my WCF service starts up correctly, my client starts up correctly, even the sending of the message to log from client to server works. But, when I shut the client down, I get SocketExceptions thrown by the server for each message that was transmitted. I know this is due to the channel not being closed properly by the client. I cannot find where I must close the channel to prevent the exceptions being thrown by my server. I have read that to manually close the channel I must use
Channel.Close();
would that be correct and where would I put that?
I want to prevent these SocketExceptions. I have found this, but it does not seem to be the correct thing to do. Correct me if I am wrong, but would the solution not use the same principles?
Unless of course I am understanding this completely wrong...
Everything is done using the config files (App.Config and NLog.Config).
Here is my LogReceiverService Target from NLog.config:
<target xsi:type="LogReceiverService"
name="logreceiver"
endpointConfigurationName="LogReceiverClient"
endpointAddress="net.tcp://server:8888/NLogServices/LogReceiverServer/logreceiverserver" />
Here is my endpoint from my app.config:
<endpoint address="net.tcp://server:8888/NLogServices/LogReceiverServer/logreceiverserver"
binding="netTcpBinding"
bindingConfiguration="LogReceiverClient"
contract="NLog.LogReceiverService.ILogReceiverClient"
name="LogReceiverClient" />
Any help or advise would greatly be appreciated.
EDIT: Extended on problem description
OK, So first, here is the Service on my host pretty much as I got it from here:
/// <summary>
/// Log service server object that logs messages.
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class LogReceiverServer : ILogReceiverServer
{
public void ProcessLogMessages(NLogEvents nevents)
{
var events = nevents.ToEventInfo("Client.");
foreach (var ev in events)
{
var logger = LogManager.GetLogger(ev.LoggerName);
logger.Log(ev);
}
}
}
I then created this class, where I inherit from LogReceiverWebServiceTarget and override protected virtual WcfLogReceiverClient CreateWcfLogReceiverClient(); method. It is exactly the same as is found on GitHub here, except that I registered on the ProcessLogMessagesCompleted event where I close the 'client':
[Target("wcftarget")]
public class WcfTarget : LogReceiverWebServiceTarget
{
protected override WcfLogReceiverClient CreateWcfLogReceiverClient()
{
WcfLogReceiverClient client;
if (string.IsNullOrEmpty(EndpointConfigurationName))
{
// endpoint not specified - use BasicHttpBinding
Binding binding;
if (UseBinaryEncoding)
{
binding = new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement());
}
else
{
binding = new BasicHttpBinding();
}
client = new WcfLogReceiverClient(binding, new EndpointAddress(EndpointAddress));
}
else
{
client = new WcfLogReceiverClient(EndpointConfigurationName, new EndpointAddress(EndpointAddress));
/*commenting this out causes multiple socket exceptions on host*/
client.ProcessLogMessagesCompleted += client_ProcessLogMessagesCompleted;
}
return client;
}
private void client_ProcessLogMessagesCompleted(object sender, AsyncCompletedEventArgs e)
{
WcfLogReceiverClient client = sender as WcfLogReceiverClient;
if (client.State == CommunicationState.Opened)
{
(sender as WcfLogReceiverClient).Close();
}
}
}
The Logger in NLog.config is:
<logger name="*" writeTo="logreceiver" minlevel="Info" />
So then if I try to log like this:
class Program
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static void Main(string[] args)
{
logger.Info("foo");
}
}
my host gives prints this to Debug:
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll
Will this have any impact on performance of the host over a long period of time?

The problem has been resolved: https://github.com/NLog/NLog/commit/138fd2ec5d94072a50037a42bc2b84b6910df641

Related

microsoft grpc-for-wcf-developers-master code fails on IIS

getting the grpc-for-wcf-developers-master, I tried to host the WCF service in the tradersys on IIS version 10 on Windows 10, which throws an exception:
Error by IIS
The AutofacServiceHost.Container static property must be set before services can be instantiated.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The AutofacServiceHost.Container static property must be set before services can be instantiated.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
I'm aware of this issue as discussed several times here, such as this post.
Yet the code by Microsft contains the appropriate autofac container.
the question is:
Is there any special settings on IIS for resolving this issue?
as I said earlier IISExpress just works fine.
seems the AppInitialize() method in which
AutofacHostFactory.Container = builder.Build();
resides, doesn't invoke.
Based on your code, I found that you need to integrate IOC with WCF, which needs to change your code.
Here is my demo:
This is my project directory.We need to add two classes: ManualProxy and CustomServiceHostFactory.
public class CustomServiceHostFactory : ServiceHostFactory
{
protected override System.ServiceModel.ServiceHost
CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ManualProxy.TargetFactory = () => new PortfolioService(new PortfolioRepository());
return base.CreateServiceHost(typeof(ManualProxy), baseAddresses);
}
}
This is the CustomServiceHostFactory class.
public class ManualProxy : IPortfolioService
{
private readonly IPortfolioService _target;
public static Func<object> TargetFactory;
public ManualProxy()
{
_target = (IPortfolioService)TargetFactory();
}
public Task<Portfolio> Get(Guid traderId, int portfolioId)
{
return _target.Get(traderId,portfolioId);
}
public Task<List<Portfolio>> GetAll(Guid traderId)
{
return _target.GetAll(traderId);
}
}
This is the ManualProxy class.
The SVC file needs to be changed as above picture.

How can my WCF service recover from unavailable message queue?

I have a WCF service that receives messages from the Microsoft Message Queue (netMsmqBinding).
I want my service to recover if the message queue is unavailable. My code should fail to open the service, but then try again after a delay.
I have code to recognize the error when the queue is unavailable:
static bool ExceptionIsBecauseMsmqNotStarted(TypeInitializationException ex)
{
MsmqException msmqException = ex.InnerException as MsmqException;
return ((msmqException != null) && msmqException.HResult == (unchecked((int)(0xc00e000b))));
}
So this should be straightforward: I call ServiceHost.Open(), catch this exception, wait for a second or two, then repeat until my Open call is successful.
The problem is, if this exception gets thrown once, it continues to be thrown. The message queue might have become available, but my running process is in a bad state and I continue to get the TypeInitializationException until I shut down my process and restart it.
Is there a way around this problem? Can I make WCF forgive the queue and genuinely try to listen to it again?
Here is my service opening code:
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
while(!_cancellationTokenSource.IsCancellationRequested)
{
try
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
catch (TypeInitializationException ex)
{
_serviceHost.Abort();
if(!ExceptionIsBecauseMsmqNotStarted(ex))
{
throw;
}
}
await Task.Delay(1000, _cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}
And here is the stack information. The first time it is thrown the stack trace of the inner exception is:
at System.ServiceModel.Channels.MsmqQueue.GetMsmqInformation(Version& version, Boolean& activeDirectoryEnabled)
at System.ServiceModel.Channels.Msmq..cctor()
And the top entries of the outer exception stack:
at System.ServiceModel.Channels.MsmqChannelListenerBase`1.get_TransportManagerTable()
at System.ServiceModel.Channels.TransportManagerContainer..ctor(TransportChannelListener listener)
Microsoft have made the source code to WCF visible, so now we can work out exactly what's going on.
The bad news: WCF is implemented in such a way that if the initial call to ServiceModel.Start() triggers a queueing error there is no way to recover.
The WCF framework includes an internal class called MsmqQueue. This class has a static constructor. The static constructor invokes GetMsmqInformation, which can throw an exception.
Reading the C# Programming Guide on static constructors:
If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.
There is a programming lesson here: Don't put exception throwing code in a static constructor!
The obvious solution lies outside of the code. When I create my hosting service, I could add a service dependency on the message queue service. However, I would rather fix this problem with code then configuration.
Another solution is to manually check that the queue is available using non-WCF code.
The method System.Messaging.MessageQueue.Exists returns false if the message queue service is unavailable. Knowing this, the following works:
private const string KNOWN_QUEUE_PATH = #".\Private$\datawarehouse";
private static string GetMessageQueuePath()
{
// We can improve this by extracting the queue path from the configuration file
return KNOWN_QUEUE_PATH;
}
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
string queuePath = GetMessageQueuePath();
while(!_cancellationTokenSource.IsCancellationRequested)
{
if (!(System.Messaging.MessageQueue.Exists(queuePath)))
{
_log.Warn($"Unable to find the queue {queuePath}. Will try again shortly");
await Task.Delay(60000, _cancellationTokenSource.Token);
}
else
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
}
}
catch(System.OperationCanceledException)
{
_log.Debug("The service start operation was cancelled");
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}

Ninject is not generating WSDL

I just started playing with Ninject for self hosted WCF services.
I ran into a problem where it isnt generating a wsdl (url?wsdl or url?singleWsdl).
I start up the service with this :
private static void StartNinjectSelfHost()
{
var someWcfService = NinjectWcfConfiguration.Create<CalculatorService, NinjectWebServiceSelfHostFactory>();
_selfHost = new NinjectSelfHostBootstrapper(CreateKernel,someWcfService);
_selfHost.Start();
}
If I revert to the standard way with this:
private static void LoadWcf()
{
if (serviceHost != null)
{
serviceHost.Close();
}
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(CalculatorService));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}
Then I get the wsdl just fine at this URL:
http://localhost:8000/ServiceModelSamples/service?singleWsdl
I'm guessing I have to tell Ninject to do this, but I'm struggling to find any good info by searching.
Any help on enabling the wsdl is appreciated.
Nevermind I'm dumb. I wanted to use "NinjectServiceSelfHostFactory" instead, now it works

JAX-RS Client API async request

I am trying to use the JAX-RS Client API to request a resource through HTTP GET, by using the following code: (I used jersey-client v2.12 and also resteasy-client v3.0.8.Final to test the implementation)
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.InvocationCallback;
public class StackOverflowExample {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
client.target("http://example.com/").request().async().get(new InvocationCallback<String>() {
#Override
public void completed(String s) {
System.out.println("Async got: " + s);
}
#Override
public void failed(Throwable throwable) {
System.out.println("Async failure...");
}
});
}
}
As I expected the String is printed almost immediately. But the process keeps running about one minute, although there isn't any code that should be executed.
The JAX-RS spec just says that we should use the InvocationCallback and nothing else that matters to my issue. But even if I use a Future the same effect happens. I also tested, if this has something to do with a timeout, which was very unlikely and wrong. The debugger shows that there are some threads running namely DestroyJavaVM and jersey-client-async-executor-0 or pool-1-thread-1 in the case of resteasy.
Do you have any idea what is going wrong here?
It is allways helpful to consult the JavaDoc. Concerning my issue it says:
Clients are heavy-weight objects that manage the client-side communication infrastructure. Initialization as well as disposal of a Client instance may be a rather expensive operation. It is therefore advised to construct only a small number of Client instances in the application. Client instances must be properly closed before being disposed to avoid leaking resources.
If I close the client properly everything is working as expected.
public class StackOverflowExample {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
// request here
client.close();
}
}

NServiceBus Sagas using NHibernate - Unable to connect to remote server

I am trying to setup NServiceBus Sagas using NHibernate persistence, but I think I have something configured incorrectly because I'm getting an error connecting to a service at 127.0.0.1:8080. I am able to get my saga to handle the command message, but after a few seconds the error message below appears in the console window and then the same command is fired again causing the handler in the saga to be invoked again. This happens repeatedly as long as I allow the application to run. I can tell NHibernate is connecting to my database because it creates a table for the saga data, however nothing is ever persisted in that table.
I think there is an error persisting the saga data, and my guess is that it may be trying to use the default RavenDb saga persistence but I'm not sure why this would be.
The error message I receive is the following:
WARN
NServiceBus.Unicast.Transport.Transactional.TransactionalTransport
[(null)] <(null)> - Failed raising 'transportmessage received' event
for message with ID=3753b476-7501-4fd8-90d0-b10aee95a578\22314
System.Net.WebException: Unable to connect to the remote server --->
System.Net.Sockets.SocketException: No connection could be made
because the target machine actively refused it 127.0.0.1:8080 at
System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot,
SocketAddress socketAddress) at
System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP) at
System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,
Socket s4, Socket s6, Socket& socket, IPAddress& address,
ConnectSocketState state, IAsyncResult asyncResult,Exception&
exception) --- End of inner exception stack trace --- at
NServiceBus.Unicast.UnicastBus.HandleTransportMessage(IBuilder
childBuilder, TransportMessage msg) at
NServiceBus.Unicast.UnicastBus.TransportMessageReceived(Object sender,
TransportMessageReceivedEventArgs e) at
System.EventHandler`1.Invoke(Object sender, TEventArgs e) at
NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.OnTransportMessageReceived(TransportMessage
msg)
A sample of the saga I am trying to use is (nothing fancy here, same thing happens whether or not I actually do something in the Handle method):
public class ItemSaga : Saga<ItemData>, IAmStartedByMessages<CreateItemCommand>
{
public void Handle(CreateItemCommand message)
{
}
}
public class ItemData : ISagaEntity
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
My endpoint configuration looks like this:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher, IWantCustomInitialization
{
public void Init()
{
var container = new UnityContainer();
container.AddNewExtension<Domain.UnityExtension>();
Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqSubscriptionStorage()
.MsmqTransport()
.PurgeOnStartup(true)
.UnicastBus()
.ImpersonateSender(false)
.DisableTimeoutManager()
.NHibernateSagaPersister()
.CreateBus()
.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
And my app.config looks like this:
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
<MsmqTransportConfig NumberOfWorkerThreads="1" MaxRetries="5"/>
<NHibernateSagaPersisterConfig UpdateSchema="true">
<NHibernateProperties>
<add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
<add Key="connection.driver_class" Value="NHibernate.Driver.Sql2008ClientDriver"/>
<add Key="connection.connection_string" Value="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"/>
<add Key="dialect" Value="NHibernate.Dialect.MsSql2012Dialect"/>
</NHibernateProperties>
</NHibernateSagaPersisterConfig>
<connectionStrings>
<add name="EventStore" connectionString="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" />
<bindingRedirect oldVersion="0.0.0.0-3.3.0.4000" newVersion="3.3.1.4000" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Just a couple of notes:
This is from a sample app that I am using to test this functionality. It uses a local database file attached to localdb, however my full application using SQL Server 2012 is exhibiting the same behavior. I also had to add a dependenteAssembly entry for NHibernate because the NServiceBus.NHibernate NuGet package currently binds to an older assembly version (as of this posting).
As you can see, I am also using Unity as my IOC, but I have replicated this with a project using Ninject as well. I am using EventStore for my domain storage which is working great. I have command handlers that handle the command and publish events through EventStore to be handled by other processes. However, I have tried disabling all of those leaving me with just my Saga as a command handler and I still get the same error.
Does anyone have any ideas of what I may be doing wrong?
I have found a workaround to my problem. It seems to be an issue with using the built-in NServiceBus profiles. I was not specifying a profile in the command line arguments of the host, so by default it was loading the NServiceBus.Production profile. The Production profile, by default, uses RavenDB for all persistence.
Looking at the NServiceBus source on GitHub, the Production Profile Handler contains the following in the ProfileActivated method:
Configure.Instance.RavenPersistence();
if (!Configure.Instance.Configurer.HasComponent<ISagaPersister>())
Configure.Instance.RavenSagaPersister();
if (!Configure.Instance.Configurer.HasComponent<IManageMessageFailures>())
Configure.Instance.MessageForwardingInCaseOfFault();
if (Config is AsA_Publisher && !Configure.Instance.Configurer.HasComponent<ISubscriptionStorage>())
Configure.Instance.RavenSubscriptionStorage();
A couple of things to note here:
The profile will always call RavenPersistence() on the
Configure instance. I have not dug into the inner workings of that
method to see if it will actually bypass configuring Raven if other
persistence is already defined, but it will always run this method.
When I attach to the NServiceBus source and debug through
this code, in the second line HasComponent returns
false causing the RavenSagaPersister configuration to be run. This
happens even if I have NHibernateSagaPerister is defined in the endpoint
configuration.
I'm not sure if this behavior is by design, a bug, or misconfiguration on my part. However my workaround was to create my own profile. I had to move the NHibernate configuration calls from my endpoint config to my new profile, but once I did that I was able to use NHibernate persistence without errors.
My custom profile looks like the following (I borrowed the logging handler from the Production profile's logging handler):
public class MyProfile : IProfile
{
}
internal class MyProfileProfileHandler : IHandleProfile<MyProfile>, IWantTheEndpointConfig
{
void IHandleProfile.ProfileActivated()
{
Configure.Instance.NHibernateUnitOfWork();
Configure.Instance.NHibernateSagaPersister();
Configure.Instance.DBSubcriptionStorage();
Configure.Instance.UseNHibernateTimeoutPersister();
}
public IConfigureThisEndpoint Config { get; set; }
}
public class MyProfileLoggingHandler : IConfigureLoggingForProfile<MyProfile>
{
void IConfigureLogging.Configure(IConfigureThisEndpoint specifier)
{
SetLoggingLibrary.Log4Net<RollingFileAppender>(null,
a =>
{
a.CountDirection = 1;
a.DatePattern = "yyyy-MM-dd";
a.RollingStyle = RollingFileAppender.RollingMode.Composite;
a.MaxFileSize = 1024 * 1024;
a.MaxSizeRollBackups = 10;
a.LockingModel = new FileAppender.MinimalLock();
a.StaticLogFileName = true;
a.File = "logfile";
a.AppendToFile = true;
});
if (GetStdHandle(STD_OUTPUT_HANDLE) == IntPtr.Zero)
return;
SetLoggingLibrary.Log4Net<ColoredConsoleAppender>(null,
a =>
{
LiteLoggingHandler.PrepareColors(a);
a.Threshold = Level.Info;
}
);
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
const int STD_OUTPUT_HANDLE = -11;
}
A final note, I also had to set all of the properties of my saga data object as virtual, per standard NHibernate practice. This became very apparent once the system was actually using NHibernate.
public class ItemData : ISagaEntity
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
}
This is a long explanation, but hopefully it'll help someone else out down the road. If anyone has suggestions on a better way to accomplish this, or the correct way to use profiles, please let me know!