I Have a web api app, inluding some SignalR functionality that has it's dependencies managed by Autofac.
SignalR, out of the box, does not support camelCased Json properties.
There's a decent fix here, but I need to integrate it with Autofac.
So.....
Here's the SignalR hub
public class PledgeHub : Hub
{
public void SendPledge(LivePledgeUpdate pledge)
{
Clients.All.sendPledge(pledge);
}
}
Here's the startup.cs class inluding the Camelcased Resolver from the article
[assembly: OwinStartup(typeof(Startup))]
namespace Filanthropy.Web
{
public partial class Startup
{
private readonly HttpConfiguration config;
public Startup()
{
config = new HttpConfiguration();
}
public void Configuration(IAppBuilder app)
{
// Set the dependency resolver to be Autofac.
var container = BuildContainer(config);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
ConfigureAuth(app);
ConfigureWebApi(config);
app.MapSignalR();
app.UseWebApi(config);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
}
private void ConfigureWebApi(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
private static IContainer BuildContainer(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
builder.RegisterType<PledgeHub>().ExternallyOwned();
GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => JsonSerializerFactory.Value);
return builder.Build();
}
private static readonly Lazy<JsonSerializer> JsonSerializerFactory = new Lazy<JsonSerializer>(GetJsonSerializer);
private static JsonSerializer GetJsonSerializer()
{
return new JsonSerializer
{
ContractResolver = new FilteredCamelCasePropertyNamesContractResolver
{
TypesToInclude =
{
typeof(SignalRHubs.PledgeHub),
}
}
};
}
}
}
I get camelCased properties just fine with everything that's served via WebApi, but not via Signalr.
I'm guessing that your problem is this:
GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => JsonSerializerFactory.Value);
If you're using Autofac as the container / dependency resolver, you want to register the serializer with Autofac, not with the soon-to-be-replaced global dependency resolver.
builder.Register(ctx => JsonSerializerFactory.Value).As<JsonSerializer>();
Also, I see you're using OWIN. When you use OWIN, you don't reference GlobalHost - you set up your hub configuration separately. The docs have an example showing how to do it:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD SIGNALR SETUP:
// Get your HubConfiguration. In OWIN, you'll create one
// rather than using GlobalHost.
var config = new HubConfiguration();
// Register your SignalR hubs.
builder.RegisterHubs(Assembly.GetExecutingAssembly());
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.Resolver = new AutofacDependencyResolver(container);
// OWIN SIGNALR SETUP:
// Register the Autofac middleware FIRST, then the standard SignalR middleware.
app.UseAutofacMiddleware(container);
app.MapSignalR("/signalr", config);
}
}
Related
I have gotten a task that contains creating a .Net 4.8 application that contains a "HttpSelfHostServer".
I'm stuck in the quest of assigning "IServiceCollection services" to config.DependencyResolver (of type System.Web.Http.Dependencies.IDependencyResolver)
I would really like not to use autofac or other frameworks, but all guids I can find are pointing toward these frameworks. Isn't Microsoft providing a way through?
I just had to solve the same issue. This is how i did it:
First I created a new facade class to map the IServiceCollection from the host builder to the interface HttpSelfHostConfiguration supports:
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Microsoft.Extensions.DependencyInjection;
namespace IntegrationReceiver.WebApi
{
public class HttpSelfHostDependencyResolver : IDependencyResolver
{
private readonly IServiceProvider sp;
private readonly IServiceScope scope;
public HttpSelfHostDependencyResolver(IServiceProvider sp)
{
this.sp = sp;
this.scope = null;
}
public HttpSelfHostDependencyResolver(IServiceScope scope)
{
this.sp = scope.ServiceProvider;
this.scope = scope;
}
public IDependencyScope BeginScope() => new HttpSelfHostDependencyResolver(sp.CreateScope());
public void Dispose() => scope?.Dispose();
public object GetService(Type serviceType) => sp.GetService(serviceType);
public IEnumerable<object> GetServices(Type serviceType) => sp.GetServices(serviceType);
}
}
This required me to get the latest NuGet package Microsoft.Extensions.DependencyInjection.Abstractions according to an answer here: How do I see all services that a .NET IServiceProvider can provide?
I then registered my HttpSelfHostServer in the service provider with this code:
services.AddSingleton(sp => new HttpSelfHostDependencyResolver(sp));
services.AddSingleton(sp =>
{
//Starting the HttpSelfHostServer with user-level permissions requires to first run a command like
// netsh http add urlacl url=http://+:8080/ user=[DOMAINNAME]\[USERNAME]
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.DependencyResolver = sp.GetRequiredService<HttpSelfHostDependencyResolver>();
return new HttpSelfHostServer(config);
});
And finally, to find my ApiController, I had to register that too in the service provider. I did that simply with:
services.AddScoped<HealthCheckController>();
For brewity, I'm just including my api controller below to illustrate how it now gets its dependencies:
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
namespace IntegrationReceiver.WebApi
{
public class HealthCheckController : ApiController
{
private readonly ServiceBusRunner serviceBusRunner;
public HealthCheckController(ServiceBusRunner serviceBusRunner)
{
this.serviceBusRunner = serviceBusRunner;
}
[HttpGet]
public async Task<HttpResponseMessage> Get()
{
var response = new
{
serviceBusRunner.RunningTasks,
serviceBusRunner.MaxRunningTasks
};
return await Json(response)
.ExecuteAsync(System.Threading.CancellationToken.None);
}
}
}
This is a pretty dumb-down implementation but works for me until I can upgrade this code to net5.
I hope it helps you too!
I am creating console application that does some file conversions. These conversions are easily done creating a model from the input file and then executing razor models for the output.
To have this working in the IDE I used Visual Studio 2015 preview and created a vnext console application that uses MVC. (You get razor support out of the box then). To get this all working you need to host the MVC app though, and the cheapest way to do that is hosting is through a WebListener. So I host the MVC app and then call it through "http://localhost:5003/etc/etc" to get the rendered views that construct the output.
But the console app is not supposed to listen to/use a port. It is just a command line tool for file conversions. If multiple instances would run at the same time they would fight to host the pages on the same port. (This could of coarse be prevented by choosing a port dynamically, but this is not what I am looking for)
So my question is how would you get this working without using a port, but using as much of the vnext frameworks as possible.
In short: how can I use cshtml files that I pass models in a console app that does not use a port using the vnext razor engine.
Here is some code I currently use:
Program.cs
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace ConsoleTest
{
public class Program
{
private readonly IServiceProvider _hostServiceProvider;
public Program(IServiceProvider hostServiceProvider)
{
_hostServiceProvider = hostServiceProvider;
}
public async Task<string> GetWebpageAsync()
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://localhost:5003/home/svg?idx=1");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
return await httpClient.GetStringAsync("");
}
}
public Task<int> Main(string[] args)
{
var config = new Configuration();
config.AddCommandLine(args);
var serviceCollection = new ServiceCollection();
serviceCollection.Add(HostingServices.GetDefaultServices(config));
serviceCollection.AddInstance<IHostingEnvironment>(new HostingEnvironment() { WebRoot = "wwwroot" });
var services = serviceCollection.BuildServiceProvider(_hostServiceProvider);
var context = new HostingContext()
{
Services = services,
Configuration = config,
ServerName = "Microsoft.AspNet.Server.WebListener",
ApplicationName = "ConsoleTest"
};
var engine = services.GetService<IHostingEngine>();
if (engine == null)
{
throw new Exception("TODO: IHostingEngine service not available exception");
}
using (engine.Start(context))
{
var tst = GetWebpageAsync();
tst.Wait();
File.WriteAllText(#"C:\\result.svg", tst.Result.TrimStart());
Console.WriteLine("Started the server..");
Console.WriteLine("Press any key to stop the server");
Console.ReadLine();
}
return Task.FromResult(0);
}
}
}
Startup.cs
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.ConfigurationModel;
namespace ConsoleTest
{
public class Startup
{
public IConfiguration Configuration { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
//Configure WebFx
app.UseMvc(routes =>
{
routes.MapRoute(
null,
"{controller}/{action}",
new { controller = "Home", action = "Index" });
});
}
}
}
I solved it using the following code:
Program.cs
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.TestHost;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.Runtime.Infrastructure;
namespace ConsoleTest
{
public class Program
{
private Action<IApplicationBuilder> _app;
private IServiceProvider _services;
public async Task<string> TestMe()
{
var server = TestServer.Create(_services, _app);
var client = server.CreateClient();
return await client.GetStringAsync("http://localhost/home/svg?idx=1");
}
public void Main(string[] args)
{
_services = CallContextServiceLocator.Locator.ServiceProvider;
_app = new Startup().Configure;
var x = TestMe();
x.Wait();
Console.WriteLine(x.Result);
Console.ReadLine();
}
}
}
Startup.cs
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.AspNet.Routing;
namespace ConsoleTest
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseServices(services =>
{
// Add MVC services to the services container
services.AddMvc();
});
//Configure WebFx
app.UseMvc(routes =>
{
routes.MapRoute(
null,
"{controller}/{action}",
new { controller = "Home", action = "Index" });
});
}
}
}
I want to add some custom serialization logic so that the converted json contains camel case properties.
For that reason i tried to replace the default IJsonSerializer with one the i found in this link:
https://github.com/SignalR/SignalR/issues/500
However there seems to be a problem. More specifically, the JsonNetSerializer and IJsonSerializer classes do not exist in any of the signalR assemblies. Is there any change that happened to the recent version of signalR in that respect?
Just to clarify this a bit, as of SignalR 2 you can't replace the serializer with one that isn't from from JSON.NET. However, the JSON.NET serializer used by SinglR can be created and set using the DependacyResolver.
Here's an example where a new JsonSerializer is created to handle reference loops:
protected void Application_Start()
{
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
serializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
var serializer = JsonSerializer.Create(serializerSettings);
GlobalHost.DependencyResolver.Register(typeof(JsonSerializer), () => serializer);
}
In SignalR 2.0 you can't replace the JsonSerializer, there's no more IJsonSerializer abstraction. It's always JSON.NET.
Here's an example of overriding the SignalR Dependency Resolver using StructureMap.
In this particular example, I'm converting to camelCase properties and converting enums as strings.
During startup:
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = new StructureMapSignalRDependencyResolver();
Here's the class:
public class StructureMapSignalRDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver
{
public override object GetService(Type serviceType)
{
object service;
if (!serviceType.IsAbstract && !serviceType.IsInterface && serviceType.IsClass)
{
// Concrete type resolution
service = StructureMap.ObjectFactory.GetInstance(serviceType);
}
else
{
// Other type resolution with base fallback
service = StructureMap.ObjectFactory.TryGetInstance(serviceType) ?? base.GetService(serviceType);
}
return service;
}
public override IEnumerable<object> GetServices(Type serviceType)
{
var objects = StructureMap.ObjectFactory.GetAllInstances(serviceType).Cast<object>();
return objects.Concat(base.GetServices(serviceType));
}
}
And StructureMap was setup with:
ObjectFactory.Configure(c =>
{
c.Scan(a =>
{
// scan the assembly that SignalR is referenced by
a.AssemblyContainingType<AppHost>();
a.WithDefaultConventions();
});
c.For<Newtonsoft.Json.JsonSerializer>()
.Singleton()
.Use(new Newtonsoft.Json.JsonSerializer
{
ContractResolver = new SignalRContractResolver(),
Converters = { new Newtonsoft.Json.Converters.StringEnumConverter() }
});
});
Here is the Contract Resolver:
public class SignalRContractResolver : Newtonsoft.Json.Serialization.IContractResolver
{
private readonly Assembly _assembly;
private readonly Newtonsoft.Json.Serialization.IContractResolver _camelCaseContractResolver;
private readonly Newtonsoft.Json.Serialization.IContractResolver _defaultContractSerializer;
public SignalRContractResolver()
{
_defaultContractSerializer = new Newtonsoft.Json.Serialization.DefaultContractResolver();
_camelCaseContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
_assembly = typeof(Connection).Assembly;
}
public Newtonsoft.Json.Serialization.JsonContract ResolveContract(Type type)
{
if (type.Assembly.Equals(_assembly))
{
return _defaultContractSerializer.ResolveContract(type);
}
return _camelCaseContractResolver.ResolveContract(type);
}
}
I'm using Windsor to manage IoC for my controllers in a WebAPI project. I've got a DependencyResolver working nicely to resolve controller dependencies, but now I'm looking to inject dependencies into a custom action filter I'm using to manage authentication.
I've looked into using a custom ActionInvoker but it's not clear from the interface that WebAPI is using how I would go about resolving property dependencies on the custom action filter attribute before it executes. Anyone have a good example of how to do this in the MVC 4 RC?
EDIT: I'm aware you can't do constructor injection on filters, because they're attributes and therefore instantiated by the .NET framework - but I'm hoping there's some point in the execution lifecycle that happens AFTER the filter is instantiated but BEFORE it gets executed, where I could run some custom code to enumerate across the filters' public properties and inject the necessary services.
Action filters are attributes. In .NET attribute the instantiation process is managed by the .NET runtime and you don't have control over it. So one possibility is to use Poor Man's Dependency Injection which I would personally advice you against.
Another possibility is to use a marker attribute:
public class MyActionFilterAttribute : Attribute
{
}
and then have the action filter using constructor injection:
public class MyActionFilter : ActionFilterAttribute
{
private readonly IFoo _foo;
public MyActionFilter(IFoo foo)
{
_foo = foo;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionDescriptor.GetCustomAttributes<MyActionFilterAttribute>().Any())
{
// The action is decorated with the marker attribute =>
// do something with _foo
}
}
}
and then register it as a global action filter in Application_Start:
IFoo foo = ....
GlobalConfiguration.Configuration.Filters.Add(new MyActionFilter(foo));
I had the same problem, but decided to go for the ServiceLocator (DependencyResolver.GetService) for this, as its in the framework it seems to me to be a valid approach
public class RequiresSessionAttribute :
ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var sessionService =
(ISessionService) actionContext
.ControllerContext.Configuration.DependencyResolver
.GetService(typeof (ISessionService));
var sessionId = HttpUtility
.ParseQueryString(actionContext.Request.RequestUri.Query)
.Get("sessionId");
if (sessionId == null
|| !sessionService.IsValid(sessionId))
throw new SessionException();
base.OnActionExecuting(actionContext);
}
}
and here is a test for this attribute, bit of a pain but possible
public class requires_sessionId
{
[Fact]
void can_call_action_with_session_id()
{
var context = GetContext("http://example.com/?sessionId=blaa");
var sut = new RequiresSessionAttribute();
Assert.DoesNotThrow(
() => sut.OnActionExecuting(context));
}
[Fact]
void can_not_call_action_without_session_id()
{
var context = GetContext("http://example.com/");
var sut = new RequiresSessionAttribute();
Assert.Throws<SessionException>(
() => sut.OnActionExecuting(context));
}
HttpActionContext GetContext(string url)
{
var sessionServiceMock = new Mock<ISessionService>();
sessionServiceMock
.Setup(x => x.IsValid(It.IsAny<string>()))
.Returns(true);
var dependancyResolverMock = new Mock<IDependencyResolver>();
dependancyResolverMock
.Setup(x => x.GetService(It.IsAny<Type>()))
.Returns(sessionServiceMock.Object);
var config = new HttpConfiguration
{
DependencyResolver = dependancyResolverMock.Object
};
var controllerContext = new HttpControllerContext
{
Configuration = config,
Request = new HttpRequestMessage(
HttpMethod.Get,
url)
};
return
new HttpActionContext
{
ControllerContext = controllerContext,
};
}
}
I am having trouble getting Castle Dynamic Proxy to intercept methods that are explicit interface implementations. I read here http://kozmic.pl/category/dynamicproxy/ that it should be possible to do this.
Here are my classes;
internal interface IDomainInterface
{
string DomainMethod();
}
public class DomainClass : IDomainInterface
{
string IDomainInterface.DomainMethod()
{
return "not intercepted";
}
}
Here is my interceptor class;
public class DomainClassInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name == "DomainMethod")
invocation.ReturnValue = "intercepted";
else
invocation.Proceed();
}
}
And here is my test (which fails);
[TestClass]
public void can_intercept_explicit_interface_implementation()
{
// Create proxy
var generator = new ProxyGenerator();
var interceptor = new DomainClassInterceptor();
var proxy = (IDomainInterface)generator.CreateClassProxy(typeof(DomainClass), interceptor);
// Invoke proxy method
var result = proxy.DomainMethod();
// Check method was intercepted -- fails
Assert.AreEqual("intercepted", result);
}
In addition to not being able to intercept the explicit interface implementation, it also seems that I am not receiving a notification of a non-proxyable member.
Here is my proxy generation hook (which acts as a spy);
public class DomainClassProxyGenerationHook : IProxyGenerationHook
{
public int NonProxyableCount;
public void MethodsInspected() {}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
NonProxyableCount++;
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return true;
}
}
Here is my test (which again fails);
[TestMethod]
public void receive_notification_of_nonproxyable_explicit_interface_implementation()
{
// Create proxy with generation hook
var hook = new DomainClassProxyGenerationHook();
var options = new ProxyGenerationOptions(hook);
var generator = new ProxyGenerator();
var interceptor = new DomainClassInterceptor();
var proxy = (IDomainInterface)generator.CreateClassProxy(typeof(DomainClass), options, interceptor);
// Check that non-proxyable member notification was received -- fails
Assert.IsTrue(hook.NonProxyableCount > 0);
}
Has anyone had success in getting DP to intercept explicit interface implementations? If so, how?
You are creating a class proxy. Class proxy only intercepts virtual methods on the class, and an explicit implementation of an interface method in C# by definition is not virtual (since it's private).
If you want to intercept methods on the interface you need to explicitly tell DynamicProxy about it
var proxy = (IDomainInterface)generator.CreateClassProxy(typeof(DomainClass), new Type[] { typeof(IDomainInterface) }, interceptor);
Also your interface is marked as internal so made sure it's public for DynamicProxy (either make the interface public or add InternalsVisibleToAttribute).
With that your first test will pass, and the method will be intercepted.