Write to ServiceEventSource from Service Fabric We

2019-04-10 19:32发布

In my Stateful service, I can write to the ServiceEventSource by calling this:

ServiceEventSource.Current.ServiceMessage(this.Context, "this is my log message");

Does anyone know how I can make that same call in my Stateless WebAPI controller? It seems like I'm unable to get the context into the controller. I noticed it's only available in my OwinCommunicationListener.

Basically, I want to be able to log my controllers like this:

public async Task<IHttpActionResult> Get(string id)
{
   ServiceEventSource.Current.ServiceMessage(this.Context, "this is my log message");
   //Do something
   return Ok(100);
}

1条回答
Evening l夕情丶
2楼-- · 2019-04-10 19:54

One way of solving this is to work with Dependency Injection and an IoC, much like you would with a regular WebAPI solution.

If you are using the out-of-the-box supplied OwinCommuncationController and the Startup class you could initialize and add a container to the Startup.ConfigureApp(...) method:

public static class Startup
{
    // This code configures Web API. The Startup class is specified as a type
    // parameter in the WebApp.Start method.
    public static void ConfigureApp(IAppBuilder appBuilder)
    {
        // Configure Web API for self-host. 
        HttpConfiguration config = new HttpConfiguration();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        // Add a DependencyResolver here

        appBuilder.UseWebApi(config);
    }
}

You could use any IoC that you like, here I'll show it for TinyIoC but similar approach for any (Windsor, Unity, Ninject, AutoFac...).

For TinyIoC add the NuGet TinyIoC and TinyIoC.AspNetExtensions and add a class that implements IDependencyResolver:

public class TinyIoCResolver : IDependencyResolver
{
    private readonly TinyIoCContainer _container;

    public TinyIoCResolver(TinyIoCContainer container)
    {
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        return _container.Resolve(serviceType);
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (TinyIoCResolutionException)
        {
            return null;
        }
    }

    public IDependencyScope BeginScope()
    {
        return new TinyIoCResolver(_container.GetChildContainer());
    }

    public void Dispose()
    {
        // Handle dispose
    }
}

Note, this is just the simples implementation, for a better look at this article http://blog.i-m-code.com/2014/04/15/tinyioc-mvc-and-webapi-configuration/

Not update your Startup to allow WebApi to use the DependencyResolver:

public static class Startup
{
    public static void ConfigureApp(IAppBuilder appBuilder, TinyIoCContainer container)
    {
       ...

        config.DependencyResolver = new TinyIoCResolver(container);

       ...
    }
}

And finally register your dependency (StatelessServiceContext) in your service:

internal sealed class WebApiService : StatelessService
{
    public TinyIoCContainer Container { get; private set; }

    public WebApiService(StatelessServiceContext context)
        : base(context)
    {
        Container = new TinyIoCContainer();
        Container.Register<StatelessServiceContext>(context);
    }

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new ServiceInstanceListener[]
        {
            new ServiceInstanceListener(serviceContext => new OwinCommunicationListener(appBuilder => Startup.ConfigureApp(appBuilder, Container), serviceContext, ServiceEventSource.Current, "ServiceEndpoint"))
        };
    }
}

Notice that you have to make a slight change to how you call the Startup.ConfigureApp method in order to supply your container as well.

Now all you have to do is to add StatelessServiceContext as a dependency in the constructor of your ApiController and store it as a member in your controller:

public ValuesController(StatelessServiceContext serviceContext) 
{
    _serviceContext = serviceContext;
}

And from within your controller actions use it:

ServiceEventSource.Current.ServiceMessage(_serviceContext, "this is my log message");

There are many variations to how you can do this, when and where you can create the container, how to resolve the controllers and so on. There should be plenty of guides on how to setup ASP.NET WebApi and IoC dependency injection.

查看更多
登录 后发表回答