I have problem with resolving component with Unity in my .NET MVC 5 app.
In my App_Start folder I have generated UnityConfig.cs and UnityMvcActivator.cs, which looks like this:
public static class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer Container => container.Value;
#endregion
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below.
// Make sure to add a Unity.Configuration to the using statements.
// container.LoadConfiguration();
container.AddNewExtension<Interception>();
container.RegisterType<ILogger, EntLibFileLogger>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(ConfigurationManager.AppSettings["logTrace"],
int.Parse(ConfigurationManager.AppSettings["logSize"])));
container.RegisterType<IUserRepository, UserRepository>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<LoggingInterceptionBehavior>());
container.RegisterType<IUserProvider, UserProvider>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<LoggingInterceptionBehavior>());
...
}
}
public static class UnityMvcActivator
{
/// <summary>
/// Integrates Unity when the application starts.
/// </summary>
public static void Start()
{
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>
/// Disposes the Unity container when the application is shut down.
/// </summary>
public static void Shutdown()
{
UnityConfig.Container.Dispose();
}
}
Interception look like this:
class LoggingInterceptionBehavior : IInterceptionBehavior
{
private readonly ILogger _logger;
public LoggingInterceptionBehavior(ILogger logger)
{
_logger = logger;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var methodDesc = $"{input.MethodBase.DeclaringType.Name}.{input.MethodBase.Name}";
var args = input.Arguments == null || input.Arguments.Count == 0
? "null"
: JsonConvert.SerializeObject(input.Arguments);
// Before invoking the method on the original target.
_logger.Log($"{methodDesc} start. Arguments: {args}", LogLevel.Info);
// Invoke the next behavior in the chain.
var result = getNext()(input, getNext);
// After invoking the method on the original target.
if (result.Exception != null)
{
_logger.Log($"{methodDesc} threw exception. {result.Exception.GetBaseException()}", LogLevel.Error);
}
else
{
_logger.Log($"{methodDesc} end", LogLevel.Info);
}
return result;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute
{
get { return true; }
}
}
I have also customized authorization filter, where is following code:
public class SayDoAuthorizeAttribute : AuthorizeAttribute
{
private readonly string[] allowedRoles;
public SayDoAuthorizeAttribute() : base()
{
}
public SayDoAuthorizeAttribute(params string[] roles)
{
allowedRoles = roles;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var userRoles = SayDoAuthorizeHelper.GetRolesAndCacheThem(httpContext);
bool authorize = false;
foreach (var role in allowedRoles)
{
if (userRoles.Contains(role))
{
authorize = true;
break;
}
}
return authorize;
}
...
}
The problem is that UnityConfig.Resolve fails on resolving IUserProvider component in following SayDoAuthorizeHelper.GetRolesAndCacheThem method. (I want to have this class static, because IsUserInRole and IsUserInRoles mehthods are also used in razor views.
public static class SayDoAuthorizeHelper
{
public static IEnumerable<string> GetRolesAndCacheThem(HttpContextBase httpContext)
{
var nameFromSession = httpContext.Session[Constants.SessionKeyUserPreselectSession];
var userName = (nameFromSession != null) ? (string)nameFromSession : httpContext.User.Identity.Name;
var rolesString = (string)httpContext.Cache.Get(userName);
if (string.IsNullOrEmpty(rolesString))
{
var userProvider = UnityConfig.Container.Resolve<IUserProvider>();
var roles = userProvider.GetUserRolesNames(userName);
rolesString = string.Join(",", roles);
//set absolute cache
var minutesToCacheRoles = double.Parse(ConfigurationManager.AppSettings[Constants.KeyCacheUserRolesInMinutes]);
httpContext.Cache.Insert(userName, rolesString, null, DateTime.Now.AddMinutes(minutesToCacheRoles), Cache.NoSlidingExpiration);
return roles;
}
return rolesString.Split(',').ToList();
}
public static bool IsUserInRole(System.Security.Principal.IPrincipal userPrincipal, string roleName)
{
var userRoles = GetRolesAndCacheThem(new HttpContextWrapper(HttpContext.Current));
return userRoles.Contains(roleName);
}
public static bool IsUserInRoles(System.Security.Principal.IPrincipal userPrincipal, string[] roleNames)
{
var userRoles = GetRolesAndCacheThem(new HttpContextWrapper(HttpContext.Current));
foreach (var roleName in roleNames)
{
if (userRoles.Contains(roleName))
{
return true;
}
}
return false;
}
}
When I have breakpoint set on line
var userProvider = UnityConfig.Container.Resolve();
then no exception is thrown, and code still continue, but I see in local variables that userProvider threw an exception of type 'System.IO.FileNotFoundException' Abb.Czopc.SayDo.BusinessLogic.Interface.IUserProvider {System.IO.FileNotFoundException}
with message "Cannot load assembly '15bd37ce9f8a41d9b9916a1ebadc536a'.". But in output window I see that assembly was loaded.
'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-1-131699797337577440): Loaded '15bd37ce9f8a41d9b9916a1ebadc536a'.
When I have registration in UnityConfig without Interception, everything works good.
container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<IUserProvider, UserProvider>();
I also tried replace InterfaceInterceptor with VirtualMethodInterceptor, but with same result.
Can anyone help? I dont know what is wrong. Thanks for help.
Solution is written in VS 2015, list of nuget packages is here:
<package id="Abb.Czopc.Common.Log" version="1.0.1" targetFramework="net451" />
<package id="Abb.Czopc.Common.Log.EntLibLogger" version="1.0.1" targetFramework="net451" />
<package id="Antlr" version="3.5.0.2" targetFramework="net451" />
<package id="AutoMapper" version="6.2.2" targetFramework="net451" />
<package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net451" />
<package id="EnterpriseLibrary.Logging" version="6.0.1304.0" targetFramework="net451" />
<package id="jQuery" version="3.3.1" targetFramework="net451" />
<package id="jQuery.Validation" version="1.17.0" targetFramework="net451" />
<package id="Microsoft.AspNet.Mvc" version="5.2.4" targetFramework="net451" />
<package id="Microsoft.AspNet.Razor" version="3.2.4" targetFramework="net451" />
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net451" />
<package id="Microsoft.AspNet.WebPages" version="3.2.4" targetFramework="net451" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net451" />
<package id="Microsoft.jQuery.Unobtrusive.Ajax" version="3.2.5" targetFramework="net451" />
<package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.9" targetFramework="net451" />
<package id="Microsoft.Net.Compilers" version="2.7.0" targetFramework="net451" developmentDependency="true" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net451" />
<package id="Modernizr" version="2.8.3" targetFramework="net451" />
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net451" />
<package id="Respond" version="1.4.2" targetFramework="net451" />
<package id="Unity.Abstractions" version="3.3.0" targetFramework="net451" />
<package id="Unity.Container" version="5.8.5" targetFramework="net451" />
<package id="Unity.Interception" version="5.5.1" targetFramework="net451" />
<package id="Unity.Mvc" version="5.0.13" targetFramework="net451" />
<package id="WebActivatorEx" version="2.2.0" targetFramework="net451" />
<package id="WebGrease" version="1.6.0" targetFramework="net451" />
Related
I'm new to mvc and I'm trying to get logging to work
I don't know how to write to log from different controlers
Logging from global.asax -> Application_Start() here logging works.
I have installed following nuget packages:
<package id="Serilog" version="2.12.0" targetFramework="net48" />
<package id="Serilog.Sinks.Console" version="4.1.0" targetFramework="net48" />
<package id="Serilog.Sinks.File" version="5.0.0" targetFramework="net48" />
<package id="SerilogWeb.Classic" version="5.1.66" targetFramework="net48" />
<package id="SerilogWeb.Classic.Mvc" version="2.1.25" targetFramework="net48" />
Global.asax file:
public class App : System.Web.HttpApplication
{
protected void Application_Start()
{
var log = new LoggerConfiguration()
.WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/bin/Logs/log.txt"))
.CreateLogger();
log.Information("Hello - Application_Start"); //Works
}
}
Controller 1
public class TestController : Controller
{
//setup log or what to do??
public ActionResult Index()
{
log.Information("Log sample 1")
return View();
}
}
Controller 2
public class AnotherTestController : Controller
{
//setup log or what to do??
public ActionResult Index()
{
log.Information("Log sample 2")
return View();
}
}
A file in appcode folder
public static class TSTUtil
{
//This is not a controller but how to setup log or what to do??
public static string GetHelp()
{
log.Information("Log sample 3")
}
}
First add the static class config of the serilog
public class App : System.Web.HttpApplication
{
protected void Application_Start()
{
var log = new LoggerConfiguration()
.WriteTo.File(System.Web.Hosting.HostingEnvironment.MapPath("~/bin/Logs/log.txt"))
.CreateLogger();
Log.Logger=log;
Log.Logger.Information("Hello - Application_Start"); //Works
}
}
Then anywhere you can just call it:
public class TestController : Controller
{
//setup log or what to do??
public ActionResult Index()
{
Log.Logger.Information("Log sample 1")
return View();
}
}
I'd like to use AOP to intercept calls to all methods within ASP.NET Controllers and ApiControllers.
Following http://structuremap.github.io/dynamic-interception/ I tried to get it to work as follows.
The interceptor at present does nothing much, but provide a way to see the method name and its attributes:
public class AuthorisationInterceptor : ISyncInterceptionBehavior
{
public IMethodInvocationResult Intercept(ISyncMethodInvocation methodInvocation)
{
var classType = methodInvocation.MethodInfo.DeclaringType;
var classAttributes = classType.Attributes;
string methodName = methodInvocation.MethodInfo.Name;
var methodAttributes = methodInvocation.MethodInfo.Attributes;
//var argument = methodInvocation.GetArgument("value");
return methodInvocation.InvokeNext();
}
}
The issue is how to attach it -- without getting errors.
I've tried a couple of different approaches, both raise the same type of error..
"Decorator Interceptor failed during object construction. Specified type is not an interface,Parameter name: interfaceToProxy"
The issue is that ASP.MVC is asking for the Controllers directly (eg: 'AboutController', and not 'IAboutController').
public class AppCoreControllerConvention : ICustomRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Attach a policy to intercept all Controllers before attaching Controllers...but it raises error.
// "Decorator Interceptor failed during object construction. Specified type is not an interface,Parameter name: interfaceToProxy"
registry.Policies.Interceptors(
new DynamicProxyInterceptorPolicy(
x => (x.IsConcrete() | !x.IsOpenGeneric()) & (x.CanBeCastTo<Controller>() | x.CanBeCastTo<ApiController>()),
new IInterceptionBehavior[]
{
new AuthorisationInterceptor(),
new AuditingInterceptor()
}
));
// Now find all Controllers/ApiControllers:
var foundControllers = types.FindTypes(
TypeClassification.Concretes | TypeClassification.Closed)
.Where(x => x.CanBeCastTo<Controller>() | x.CanBeCastTo<ApiController>())
.ToArray();
// to register them with StructureMap as themselves (ie, no 'Use' statement):
foreach (var serviceType in foundControllers)
{
registry.For(serviceType).LifecycleIs(new UniquePerRequestLifecycle());
// Although when I tried use/fore, it also raised {"Specified type is not an interface\r\nParameter name: interfaceToProxy"}
// AttachBehaviour(registry, serviceType);
}
}
//private static void AttachBehaviour(Registry registry, Type serviceType)
//{
// var dynamicProxyInterceptorType = typeof(StructureMap.DynamicInterception.DynamicProxyInterceptor<>);
// var genericDynamicProxyInterceptorType = dynamicProxyInterceptorType.MakeGenericType(new[] { serviceType });
// var interceptorBehaviors = new StructureMap.DynamicInterception.IInterceptionBehavior[]
// {
// new AuthorisationInterceptor(),
// new AuditingInterceptor()
// };
// var args = new[] { interceptorBehaviors };
// // Create
// IInterceptor interceptor =
// (StructureMap.Building.Interception.IInterceptor)Activator.CreateInstance(
// genericDynamicProxyInterceptorType,
// (BindingFlags)0,
// null,
// args,
// null);
// // Attach interceptors to Service:
// registry.For(serviceType).Use(serviceType).InterceptWith(interceptor);
//}
}
I'm using:
<package id="StructureMap" version="4.5.1" targetFramework="net461" />
<package id="StructureMap.DynamicInterception" version="1.1.1" targetFramework="net461" />
<package id="StructureMap.MVC5" version="3.1.1.134" targetFramework="net461" />
<package id="structuremap.web" version="4.0.0.315" targetFramework="net461" />
<package id="StructureMap.WebApi2" version="3.0.4.125" targetFramework="net461" />
Thanks for any recommendation on how to proceed.
PS: I'm not sure if I exactly understood what https://stackoverflow.com/a/47582778/9314395 was recommending, but the following did not magically produce any interception:
registry.For<IController>().InterceptWith(new DynamicProxyInterceptor<IController>(new IInterceptionBehavior[]{new AuthorisationInterceptor()}));
I am trying to integrate Ninject in my WebAPI 2 project but I am getting following error:
{
"message": "An error has occurred.",
"exceptionMessage": "An error occurred when trying to create a controller of type 'BrandController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType": "System.InvalidOperationException",
"stackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"innerException": {
"message": "An error has occurred.",
"exceptionMessage": "Type 'ADAS.GoTango.WebApi.Controllers.BrandController' does not have a default constructor",
"exceptionType": "System.ArgumentException",
"stackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
My package config is:
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.Common.WebHost" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.WebApi" version="3.2.4.0" targetFramework="net45" />
<package id="Ninject.Web.WebApi.WebHost" version="3.2.4.0" targetFramework="net45" />
<package id="Ninject.WebApi.DependencyResolver" version="0.1.4758.24814" targetFramework="net45" />
My code :
public class BrandController : BaseApiController
{
readonly BrandsBusiness _brandsBusiness;
public BrandController(BrandsBusiness brandsBusiness)
{
_brandsBusiness = brandsBusiness;
}
//public BrandController()
//{
// _brandsBusiness = new BrandsBusiness(new BrandEfStore());
//}
public IHttpActionResult Get()
{
try
{
var allActiveBrands = _brandsBusiness.GetAllActiveBrands();
return Ok(allActiveBrands);
}
catch (Exception exception)
{
Logger.Error(exception);
return InternalServerError();
}
}
}
and NinjectWebCommon.cs file is
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
var configuration = new HttpConfiguration();
kernel.Bind<DefaultModelValidatorProviders>().ToConstant(new DefaultModelValidatorProviders(configuration.Services.GetServices(typeof(ModelValidatorProvider)).Cast<ModelValidatorProvider>()));
kernel.Bind<BrandsBusiness>().ToSelf().InRequestScope();
kernel.Bind<IBrandManagement>().To<BrandEfStore>().InRequestScope();
}
I have alredy tried :
Parameterless constructor error with Ninject bindings in .NET Web Api 2.1
Ninject.ActivationException thrown only on first web request (WebAPI 2, OWIN 3, Ninject 3)
but none of them worked.
While I don't know Ninject, I'd imagine that you'll need to make sure that the CreateKernel method is called. You'd normally add an Application_Start method in your global.asax.
You may need to make the CreateKernel method internal or public in order to be able to call if from there.
I am working on Struts2 Interceptors .
I have read that Struts2 Interceptors are just like Filters , which execute before the Action class is executed and one more time after processing the result ( Please correct me if i am wrong ) , that is two times
But when i ran the below code , the interceptors are executed only once .
Please correct me if i made any mistake .
Please see my code below :
This is My Struts.xml file
<struts>
<constant name="struts.devMode" value="true" />
<package name="test" extends="struts-default">
<interceptors>
<interceptor name="loginkiran" class="vaannila.MyLoginInterCeptor" />
</interceptors>
<action name="HelloWorld" class="vaannila.HelloWorld" method="kiran">
<interceptor-ref name="loginkiran" />
<result name="SUCCESS">/success.jsp</result>
</action>
</package>
</struts>
This is my Action class
public class HelloWorld
{
public HelloWorld() {
}
public String kiran() {
System.out.println("iNSIDE THE aCTION CLASS");
return "SUCCESS";
}
}
This is my Interceptor class
public class MyLoginInterCeptor implements Interceptor {
#Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("Destroying Interceptor");
}
#Override
public void init() {
}
#Override
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = (HttpServletRequest) ActionContext
.getContext().get(ServletActionContext.HTTP_REQUEST);
System.out.println("iNSIDE THE iNTERCEPTOR");
return invocation.invoke();
}
}
This is my JSP File :
<html>
<body>
<%
System.out.println("iNSIde THE jsp");
%>
</body>
</html>
The Output for the above code is this :
iNSIDE THE iNTERCEPTOR
iNSIDE THE aCTION CLASS
iNSIde THE jsp
Interceptors are not executed twice (nor are filters): interceptors (and filters) wrap the action (or servlet/etc.)
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("Before action invocation...");
return invocation.invoke();
System.out.println("After action invocation...");
}
I have two applications on IIS for development. First WCF application that contains all the logic and communication with database (we call this Server). And another ASP.NET MVC 3 application that has reference to WCF application (we call this Client).
I have issue connected with mixing WCF web.config configuration with Unity IoC custom service host and custom behavior.
When all configuration is done by Unity it creates simple BasicHttpBinding, but my requirement is to make it secure with Certificate Authorization, so I need wsHTTPBinding.
------------- Configuring for BasicHttpBinding ------------
At the beginning look at common Unity implementation for WCF:
internal class UnityInstanceProvider : IInstanceProvider
{
private readonly IUnityContainer container;
private readonly Type contractType;
public UnityInstanceProvider(
[NotNull] IUnityContainer container,
[NotNull] Type contractType)
{
this.container = container;
this.contractType = contractType;
}
#region IInstanceProvider Members
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return container.Resolve(contractType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
container.Teardown(instance);
}
}
internal class UnityServiceBehavior : IServiceBehavior
{
private readonly IUnityContainer container;
public UnityServiceBehavior(
[NotNull] IUnityContainer container)
{
this.container = container;
}
#region IServiceBehavior Members
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
if (endpointDispatcher.ContractName != "IMetadataExchange")
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(container, serviceDescription.ServiceType);
}
}
}
}
#endregion
}
public class UnityServiceHost : ServiceHost
{
private readonly IUnityContainer container;
public UnityServiceHost(
[NotNull] IUnityContainer container,
[NotNull] Type serviceType,
Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
this.container = container;
}
protected override void OnOpening()
{
base.OnOpening();
if (Description.Behaviors.Find<UnityServiceBehavior>() == null)
{
Description.Behaviors.Add(new UnityServiceBehavior(container));
}
}
}
public class UnityServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
IUnityContainer container = new UnityContainer();
UnityContainerConfigurator.Configure(container);
return new UnityServiceHost(container, serviceType, baseAddresses);
}
}
WCF application web.config contains only basic information:
None endpoints, none service definition.
Now imagine that we have SecurityService with definition:
<%# ServiceHost Language="C#" Debug="true"
Service="myNamespace.SecurityService"
Factory="myNamespace.UnityServiceHostFactory" %>
Now I can add service reference to SecurityService to my Client.
A this step it generates in client web.config:
<basicHttpBinding>
<binding name="BasicHttpBinding_ISecurityService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
<endpoint address="http://localhost/wcf-app/SecurityService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISecurityService"
contract="SecurityServiceReference.ISecurityService" name="BasicHttpBinding_ISecurityService" />
At this point I configure this for Unity:
container.RegisterType<SecurityServiceClient>(new InjectionConstructor());
And in Client application I can use it simply by (I don't mention here constructor injection):
var securityService = DependencyResolver.Current.GetService<SecurityServiceClient>();
And this all works! But It don't if I want to use wsHTTPBinding ...
------------- Configuring for wsHTTPBinding ------------
To enable wsHTTPBinding I configured it inside web.config of WCF Application. As a remainder for BasicHttpBinding it didn't contained any information concerning binding, endpoin, etc.
But now for wsHTTPBinding I added:
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="myNamespace.SecurityService">
<endpoint address="" binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
name="wsHttpEndpoint" contract="myNamespace.ISecurityService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<serviceCertificate findValue="CN=myClientCert" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
And after adding service reference to Client application it generates:
<wsHttpBinding>
<binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
I manually added behaviorConfiguration="CertBehavior", that is:
<behaviors>
<endpointBehaviors>
<behavior name="CertBehavior">
<clientCredentials>
<clientCertificate findValue="CN=myClientCert"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
And now when I want to resolve it using Unity:
var securityService = DependencyResolver.Current.GetService<SecurityServiceClient>();
I get always null...
What is funny when I create simply instance by:
var client = new SecurityServiceReference.SecurityServiceClient();
It works fine... So for sure issue is not connected with wrong wsHttpBinding configuration but rather combining Unity + wsHttpBinding from web.config...
Can any one help me with this issue?
Daniel
Ok, I figured it out.
Ladislav you were right that it should show an exception.
UnityDependencyResolver was simply catching it.
internal class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer container;
public UnityDependencyResolver([NotNull] IUnityContainer container)
{
this.container = container;
}
#region IDependencyResolver Members
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
I also had to explicitly set certificate locations for the certificates:
<serviceCertificate findValue="CN=myClientCert"
storeName="My"
x509FindType="FindBySubjectDistinguishedName"
storeLocation="LocalMachine"
/>
<clientCertificate findValue="CN=myClientCert" storeName="My"
x509FindType="FindBySubjectDistinguishedName"
storeLocation="LocalMachine"
/>
Now it works fine.