TraceListener in OWIN Self Hosting - c#

I am using Microsoft.Owin.Hosting to host the following, very simple web app.
Here is the call to start it:
WebApp.Start<PushServerStartup>("http://localhost:8080/events");
Here is the startup class I am using:
public class PushServerStartup
{
public void Configuration(IAppBuilder app)
{
app.MapHubs();
}
}
I am running this inside a console application that does a lot of other things including routing trace writing to certain files etc. But all of a sudden (when activating the OWIN hosting) I am seeing trace messages written to the console that are normally routed somewhere else.
Obviously there are some trace listeners active in the OWIN hosting framework. How can I switch them off?

I had the same issue, I was self hosting 4 instances in one process and for each request was getting 4 lots of messages traced to console.
I simply removed the TraceListener instance
Trace.Listeners.Remove("HostingTraceListener")
"HostingTraceListener" is defined in the owin source code so I guess could change
- http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Hosting/Engine/HostingEngine.cs
I did this after
WebApp.Start(...

An alternative to the answer from meilke that works with latest Katana self-host (2.1.0):
StartOptions options = new StartOptions("http://localhost:8080/events");
// disable built-in owin tracing by using a null traceoutput
options.Settings.Add(
typeof(Microsoft.Owin.Hosting.Tracing.ITraceOutputFactory).FullName,
typeof(NullTraceOutputFactory).AssemblyQualifiedName);
using (WebApp.Start<PushServerStartup>(options))
NullTraceOutputFactory is similar to DummyFactory but using StreamWriter.Null instead of StringWriter:
public class NullTraceOutputFactory : ITraceOutputFactory
{
public TextWriter Create(string outputFile)
{
return StreamWriter.Null;
}
}

I found a solution myself. After studying the Katana source code it seems like you need to register your own ITraceOutputFactory instance to overrule the default trace listener (which is writing to the console).
Here is the new start call:
var dummyFactory = new DummyFactory();
var provider = ServicesFactory.Create(
defaultServiceProvider => defaultServiceProvider.AddInstance<ITraceOutputFactory>(dummyFactory));
using (WebApp.Start<Startup>(provider, new StartOptions("http://localhost:8090")))
{
Console.ReadLine();
}
And here is a dummy trace factory (maybe not the best solution but you can replace it with something serving your purpose a little better):
public class DummyFactory : ITraceOutputFactory
{
public TextWriter Create(string outputFile)
{
return TextWriter.Null;
}
}

Related

Application Insights is not including properties set by custom ITelemetryInitializer

(Added UPDATE 1 below which I think answers this question)
In a fairly simple ASP.NET Core 2 web app I have initialized in Program like this:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
I haven't configured an instrumentation key in appSettings.json yet because for now I'm running locally. When I run my app and force an exception on load of my home page I can see the exception logged in Visual Studio's telemetry search for Application Insights.
I now want to capture some details about the request in every logged event. I've followed some guidance and created an implementation of ITelemetryInitializer:
public class CustomTelemetryInitializer : ITelemetryInitializer
{
private const string UserIdKey = "UserId";
private readonly IUserService _userService;
public CustomTelemetryInitializer(IUserService userService)
{
_userService = userService;
}
public void Initialize(ITelemetry telemetry)
{
if (!(telemetry is RequestTelemetry requestTelemetry)) return;
var props = requestTelemetry.Properties;
if (!props.ContainsKey(UserIdKey))
{
var user = _userService.GetCurrentUser();
if (user != null)
{
props.Add(UserIdKey, user.UserId);
}
}
}
}
This is largely following this guide. IUserService is just a service which uses IHttpContextAccessor to get the current ClaimsPrincipal. You can see I'm trying to add the user's ID to the custom telemetry properties.
I've registered this ITelemetryInitializer in Startup like this:
services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
When I run my app again, I can see the debugger running through CustomTelemetryInitializer and setting the property correctly. However, when I review the events logged in app insights, the custom property is not included. They look identical to the screenshot above.
I've tried moving the app insights initialization out of Program and instead initializing it in Startup after registering the ITelemetryInitializer using services.AddApplicationInsightsTelemetry(), but this makes no difference.
Anyone know what I'm doing wrong?
UPDATE 1
I've realised I made a mistake. My custom properties are being included for Request events after all. But not the Exception events. But I've now realised that these Exception events take a different implementation of ITelemetry in Initialize i.e. TraceTelemetry. So I hadn't realised I was excluding these events from my custom properties.
Glad you figured it out.
All ITelemetry implementations in the SDK implements, ISupportProperties which gives it Properties collection. If you want to attach properties to every telemetry, you can cast to ISupportProperties and set props.

c# 4.0 service as client to connect a signalr(1.2.2) hub

I worte a server class as DLTransMonCore.cs using C# .Net 4.0.
DLTransMonCore.cs in DLTransMonCore DLL Project
public void MonStart() {
var client = new WebSignalrClient();
client.HubUrl = "http://10.20.30.40/MyApp";
client.HubName = "MyAppHub";
client.InitialSignalrHub();
}
WebSignalrClient.cs in WebSignalrClient DLL Project
public string HubUrl;
public string HubName;
public void InitialSignalrHub() {
var hubConnection = new HubConnection(HubUrl);
var hubProxy = hubConnection.CreateHubProxy(HubName);
hubConnection.Start().Wait();
}
This server will connect to a web site by using signalr(1.2.2). And listen some ports use socket as a socket server.
1st Scenario,
I use a console application (Program.cs) to instance the DLTransMonCore class and start it.
Everything is work fine.
Program.cs
static void Main(string[] args) {
var core = new DLTransMonCore();
core.MonStart();
Console.Readkey();
}
2nd Scenario,
I make a windows service (Service1.cs) to instance DLTransMonCore class and start it. When I try to launch the "Service1" in Windows Services, the "Service1" will start for about 10 seconds and then auto stopped by Windows.
Service1.cs
protected override void OnStart(string[] args) {
var core = new DLTransMonCore();
core.MonStart();
}
I wrote a log file to find which line last executed was:
hubConnection.Start().Wait(); (in WebSignalrClient.cs),
and it never reach the next line.
3rd Scenario,
I make another windows service (Service2.cs) to instance WebSignalrClient directly. And this "Service2" start successfully. (hubConnection.Start().Wait(); is executed successfully and reach the next line)
Service2.cs
protected override void OnStart(string[] args) {
var client = new WebSignalrClient();
client.HubUrl = "http://10.20.30.40/MyApp";
client.HubName = "MyAppHub";
client.InitialSignalrHub();
}
Why the Service1 be fail and the Service2 be success?
Any comment will be appreciate!
Edit:
The description of this post is simplify from my "Original Solution". The Original Solution has lots of Models, Repositories, Interfaces, Utilities, Extensions, Projects...etc.
So I have to simplify it to describe my problem.
But I just created another "New Solution", with the minimized code to test Scenario2 and Scenario3.
Then I found the "New Solution" were worked. It's really bother me...
Now I have to retest and review my code in the "Original Solution".
But if you have any suggestions or comments, please still comment it.
Thank you!
Edit 2:
Dear all, This pattern is no problem.
I found my problem in the "Original Solution".
The problem is : NullReferenceException.
The reason is : When Windows starts the Service, the working directory IS NOT where your Service.exe existed.
In my solution, I have my customize configuration file in that Service's location. And the Service will get the configuration by using the filename directly. Then, the Service will got a null object, and the NullReferenceException when Service Starting is trying to access the config.
I can't explain why but i had the same issue as i wanted a self hosted server using windows service and i never figured out why it was so unstable, what i can suggest is to use Owin selfhost as i switched to it using signalR and it's much more reliable than windows service.

While working on IIS System.Diagnostic.Trace.CorrelationManager.ActivityId is generated empty

we are using System.Diagnostic.Trace.CorrelationManager class to accomplish end to end tracing.The class has a guid property "ActivityId" which is generated by default on every request.
Our tracing is working well on iis express but after deploy project on iis System.Diagnostic.Trace.CorrelationManager.ActivityId is not generated.
IIS Express will probably have a module configured which will be setting the ActivityId on the CorrelationManager. I believe a number of modules do this, one example is FailedRequestsTracingModule (you don't actually need be monitoring failed requests so may have less of a performance overhead) and many APM tools like Stackify will do the same.
If Trace.CorrelationManager.ActivityId is empty you could ensure IIS is configured to use a module that sets it or alternatively you can create a simple one like:
public class SetActivityIdModule : IHttpModule {
public void Init(HttpApplication context) {
context.BeginRequest += (sender, args) =>
{
if (Trace.CorrelationManager.ActivityId == Guid.Empty) Trace.CorrelationManager.ActivityId = Guid.NewGuid();
};
}
public void Dispose() {}
}
The solutions i came up with enabling request tracing module on iis but that leads too much overload on server so i decided to generate it by my self instead of trusting on iis

Path not found error

I installed SignalR 2.0-rc1, and:
1: Created a hub:
public class Socials : Hub
{
public void PublicChat(string message)
{
Clients.All.PublicChat(new { message });
}
}
2: Created a startup class:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
3: Registered it in web.config:
<add key="owin:AppStartup" value="Scyk.Startup, Scyk"/> //Scyk is my main namespace, also a project name, I placed Startup class in there.
Now, https://myhost.com/signalr/hubs is generating javascript file properly, but when I open developer console in my browser, I see that it has not connected, but:
There is an asp error saying that path /signalr/connect was not found (why is it trying to access /signalr/connect? Is that normal? If so, then this must be purely routing problem, how do I solve it?)
In my console, I see that there is a EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection. error. I am not sure if this is related, but it started to show up today, wasn't there before.
What am I doing wrong?
Any path beginning with /signalr should be routed through OWIN so signalr can handle the request.
It is normal for the client to try to access /signalr/connect after accessing /signalr/negotiate. /signalr/connect is the endpoint where SignalR establishes its WebSockets/Server-Sent Events/Forever Frame/Long Polling connections.

WCF/REST Logging

I was wondering if someone could show me how to log a simple request/response from my wcf rest service.
I am self hosting with a console application on the localmachine:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));
WebHttpBinding binding = new WebHttpBinding();
//binding.Security.Mode = WebHttpSecurityMode.Transport;
host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
Console.ReadLine();
}
}
}
I was really hoping all that would be required is something added to the hosting console app. I tryed following this but it was abit confusing http://blogs.msdn.com/b/carlosfigueira/archive/2011/04/19/wcf-extensibility-message-inspectors.aspx
Just to note I am not using any app.config or web.config files.
EDIT:
I also cannot use any third party products for this.
Are you talking about logging for debugging purposes or for monitoring in a live service?
If you are debugging you can just switch on WCF tracing. It will produce a very comprehensive log and there is a good free tool for viewing the log that comes as part of the Windows SDK - I presume when you say you can't use third party product it doesn't include built-in .Net and Windows SDK features...
http://msdn.microsoft.com/en-us/library/ms733025.aspx
A common way to handle this is with Aspect-Oriented Programming (AOP) using the Castle Dynamic Proxy library. The idea is that you can decorate/proxy your service implementation with a dynamic class that intercepts every single method called on your service. No matter what method is called on your service, they'll be "intercepted" by your proxy and sent to a single method where you can log what you want and then you can finish the original call. Here's a quick sample of what that looks like:
public class LoggingInterceptor : IInterceptor
{
// No matter what service method is called, it's funneled through here.
public void Intercept(IInvocation call)
{
MyLogger.Info("Starting call: " + call.Method.Name);
// Actually invoke whatever method was originally called
call.Proceed();
MyLogger.Info("Finished call: " + call.Method.Name);
}
}
Now you need to create a proxy of your service class that uses this interceptor for all of its method calls. You can pretty up and abstract as necessary, but this is the basic jist:
using Castle.DynamicProxy;
...
// Create your service object and then create a dynamic proxy of the object
// that will inject your logging interceptor logic.
ProxyGenerator generator = new ProxyGenerator();
RawDataService service = new RawDataService();
RawDataService proxy = generator.CreateClassProxyWithTarget<RawDataService>(
service,
new LoggingInterceptor());
// Register your proxy object, not the raw service w/ WCF
WebServiceHost host = new WebServiceHost(proxy, new Uri(baseAddress));
... rest of your code as it was ...
Now any call made to your RawDataService will go through the Intercept() method first and when it calls Proceed() your actual implemented service logic will happen. You can update the interceptor to handle exceptions, include a StopWatch and log parameters as needed but that's the basic idea.
My example shows you the brute force way of setting this up. The "cleaner" solution would be to use IoC to create your service instance/proxy but this should get your code doing what you want right now. For further reading, here's a link to the Castle project's tutorial on using its AOP hooks:

Categories

Resources