How to debug into attribute code that is from nuget? - c#

Setup
I have a method with attribute on it that I created. I have packed the attribute into a nuget package (debug symbol mode) like I do when I want to debug into nuget packages.
Question
How can I step into this attribute? Do I need to put some other "step into this" attribute into my attribute code? I have only found the attribute that stops my from debugging DebuggerStepThroughAttribute but nothing that will allow me to explicitly stop when in debug (witch you of course don´t need normally).
I hope I have explained this well enough.
Edit (more info)
Jordan suggested calling GetCustomAttributes in the method but that is not an option (at the least in my case). My attribute is doing a token validation on the API call so you are not allowed (401) into the method if the code in the attribute denies it access. And also I can´t put a brake point into the nuget packgage, I need to be able to step into that code.
Edit 2 (finally... code)
So finally there is code.. I did´t think I needed one but here we are :-).
I have implemented my own attribute (as you can do) where there is code I would love to be able to debug into.
public class TokenAuthenticate : ActionFilterAttribute, IAuthenticationFilter
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
public bool AllowMultiple => true;
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
//... where I want to debug into
}
}
This attribute then just goes on the method or class like this [TokenAuthenticate ]

According to MSDN, Attributes are instantiated lazily:
It's important to note that these Attribute objects are instantiated
lazily. That is, they won't be instantiated until you use
GetCustomAttribute or GetCustomAttributes. They are also instantiated
each time. Calling GetCustomAttributes twice in a row will return two
different instances of ObsoleteAttribute.
If you need to step into them you should be able to do this by calling GetCustomAttributes on the Type in question and placing a break point inside the Attribute.

In my case I had to debug a custom attribute that I created. I came to an peculiar solution, but it worked for me.
You can add a constructor to your TokenAuthenticate class and invoke it from your Startup.cs for example, if you are working with WebApi.
public void Configure(...)
{
#if DEBUG
// Hack to debug your custom attribute, put a breakpoint here
var myVar = new TokenAuthenticate ();
#endif
Then you can step into the constructor when your web project is starting... and when the code of your TokenAuthenticate class appears, you can put a breakpoint where you want it the debugger to stop in future.
In case you have your custom attribute in your own nuget package. you can include the PDB file into your generated nuget package, with this settings at the *.csproj file used to generate de nupkg.
<IncludeSymbols>true</IncludeSymbols>
I hope this works for you and purity detractors not to be angry with me.
Reference: Including pdb files into nupkg

Related

ASP.NET Web API caches action filter attributes across requests

There seems to be some weird behavior in ASP.NET Web API (4.0.30506) that I haven't witnessed before.
What I'm seeing is that the same action filter attribute instance is reused over Web API requests. This is especially a problem in case this attribute gets dependencies injected to it, since those dependencies might be specific to the web request. I'm aware that it's better for attributes to be passive, but my assumption was that action filter attributes where not cached.
I searched for any articles, blog posts or Microsoft change logs that described this and the reason behind this, but I couldn't find a single thing. That makes me wonder whether there is something wrong with my configuration that makes this happening. Thing is however, that I'm able to reproduce this issue in a new and empty Visual Studio 2012 Web API project.
What I did was create a new empty project using the Visual Studio 2012 ASP.NET MVC 4 Web Application project with the "Web API" template. It comes with the Web API 4.0.20710.0 NuGet package. After that I added the following attribute:
[DebuggerDisplay("{id}")]
public class TestFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute {
private static readonly List<int> used = new List<int>();
private static int counter;
private readonly int id;
public TestFilterAttribute() {
this.id = Interlocked.Increment(ref counter);
}
public override void OnActionExecuting(HttpActionContext actionContext) {
// Just for testing: I would expect this line never to throw, but it does.
if (used.Contains(this.id)) throw new Exception("WAT?");
used.Add(this.id);
base.OnActionExecuting(actionContext);
}
}
And I add this attribute to the ValuesController (part of the default template):
public class ValuesController : ApiController {
// GET api/values
[TestFilterAttribute]
public IEnumerable<string> Get() {
return new string[] { "value1", "value2" };
}
// ...
}
Now when I start the project, go to the /api/values in the browser and refresh that page a few times, the "WAT?" exception is thrown.
Is this normal behavior of Web API and if so, what's the reasoning about this? Or Did I miss some memo about this change somewhere? Does this make Web API attributes extra unsuited for doing dependency injection? Or am I'm doing something wrong?
Web API is built on top of MVC, thus it uses a lot of it's functionality.
Attribute instance re-usability is part of the aggressive caching introduced by MVC 3. This means that the same Attribute instance will most likely be used with all the Actions it is applied on. MVC pipeline will do it's best at trying to treat your Attribute class like a Singleton.
Because the same Attribute instance is reused, it's Constructor is not called and id is not incremented. If, for example, you increment id inside OnActionExecuting, all will work well.
You can still do everything you want with your Attribute. You only need to keep in mind that you are not guaranteed to always get a new instance created. The constructor shouldn't contain anything but initial initialization.
public TestFilterAttribute() {
// Instance will be reused thus this will not be called for each Action
}
public override void OnActionExecuting(HttpActionContext actionContext) {
// Called on each Action
}

Getting Filter.OnAuthorization to run before Controller.OnAuthorization

I have an existing site which has a base controller class for all of its controllers which overrides the implementation of OnAuthorization. In the simplest cut down form:
protected override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
//Do Stuff
}
This all works fine and well and does what it wants at the right time. I now want to add a new global authorization that will run before all other authorisation attributes. For test purposes this attribute looks like this:
public class TestFilterAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var text = "debug point";
return;
}
}
And is added to the Global Filters like this:
filters.Add(new TestFilterAttribute());
My problem is that the OnAuthorization of the controller always seems to run before my filter's one. Is there any way that I can change this? I've tried playing with the order property that you can set when adding it to the global filter collection but that doesn't seem to help.
I could probably move the logic of the Controller's OnAuthorization into a new filter attribute when order would probably be usable but I'd rather avoid major code restructuring if there is an easier way to do it.
I've been searching for information on the Controller.OnAuthorization method but the best I have found is http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx which only talks about filters. I had assumed that they would work the same way on Controllers but they seem to be getting treated specially, in particular not respecting the order (not even int.MinValue gets in first so its not just that the controller has a very low order by default).
So any suggestions on how to get an auth filter to run as the very first thing?
The final solution used was to refactor the code. I took all of the methods that can be run on a filter attribute (eg OnAuthorization, OnActionExecuting, etc.) and moved them onto attributes named for the classes they came from. So the OnAuthorization from BasicController became the same method on BasicControllerAttribute.
These attributes were then applied to the controllers and the attributes are then inherited by all of the classes that subclass from BasicController which essentially maintains the same functionality.
However the attribute can have its Order set that allows you to play around with the running order however you want.
My takeaway from this was to never override those methods on the controller and to always use attributes. :)
I had a related problem with the Controller.OnAuthorization and the AuthorizationFilter.OnAuthorization methods order of execution.
The short answer is: you can't override that Controller.OnAuthorization
runs prior to other filters.
Detailed answer on the question 'why is it so?' is in the code from
ASP.NET MVC sources below.
There is also nice blog post on filter ordering.
Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
FilterProviders.cs
namespace System.Web.Mvc
{
public static class FilterProviders
{
static FilterProviders()
{
Providers = new FilterProviderCollection();
Providers.Add(GlobalFilters.Filters);
Providers.Add(new FilterAttributeFilterProvider());
Providers.Add(new ControllerInstanceFilterProvider());
}
public static FilterProviderCollection Providers { get; private set; }
}
}
ControllerInstanceFilterProvider.cs
using System.Collections.Generic;
namespace System.Web.Mvc
{
public class ControllerInstanceFilterProvider : IFilterProvider
{
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
if (controllerContext.Controller != null)
{
// Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
}
}
}
}

Ensure that HttpConfiguration.EnsureInitialized()

I've installed Visual Studio 2013 and when I run my app I get the error below.
I've got no idea as to where I'm to initialized this object.
What to do?
Server Error in '/' Application.
The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.
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 object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.
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.
Stack Trace:
[InvalidOperationException: The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.]
System.Web.Http.Routing.RouteCollectionRoute.get_SubRoutes() +101
System.Web.Http.Routing.RouteCollectionRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) +63
System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext) +107
System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +233
System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +60
System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +82
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18408
This is for AlumCloud
If you do it at the end of Application_Start it will be too late, as WebApiConfig.Register has been called.
The best way to resolve this is to use new initialization method by replacing in Global.asax :
WebApiConfig.Register(GlobalConfiguration.Configuration);
by
GlobalConfiguration.Configure(WebApiConfig.Register);
See #gentiane's answer below for the correct way to handle this now.
At the end of the Application_Start method in Global.Asax.cs try adding:-
GlobalConfiguration.Configuration.EnsureInitialized();
I actually got this error when I was using Attribute Routing within my WebApi.
I had
[Route("webapi/siteTypes/{siteTypeId"]
instead of
[Route("webapi/siteTypes/{siteTypeId}"]
for my route and got this error. I had simply missed out the closing curly bracket. Once I added it back in, this error didn't occur again.
This is old, but is the first result on google when searching for this error. After quite a bit of digging I was able to figure out what was going on.
tldr:
All GlobalConfiguration.Configure does is invoke your action and call EnsureInitialized(). config.MapAttributeRoutes() must be called before EnsureInitialized() since EnsureInitialized only runs once.
Meaning: if you're coming from an existing Mvc project, all you have to do is:
Add
GlobalConfiguration.Configuration.EnsureInitialized();
to the bottom of your Application_Start method.
OR
Move your entire configuration into a single call to GlobalConfiguration.Configure:
GlobalConfiguration.Configure(config =>
{
WebApiConfig.Register(config);
config.MapAttributeRoutes();
...
});
Digging Deeper
HttpConfiguration.Configuration has an "Initializer" property defined like this:
public Action<HttpConfiguration> Initializer;
HttpConfiguration.EnsureInitialized() runs this action and sets _initialized to true
public void EnsureInitialized()
{
if (_initialized)
{
return;
}
_initialized = true;
Initializer(this);
}
HttpConfiguration.MapAttributeRoutes calls internal method AttributeRoutingMapper.MapAttributeRoutes which sets HttpConfiguration.Initializer
public static void MapAttributeRoutes(...)
{
RouteCollectionRoute aggregateRoute = new RouteCollectionRoute();
configuration.Routes.Add(AttributeRouteName, aggregateRoute);
...
Action<HttpConfiguration> previousInitializer = configuration.Initializer;
configuration.Initializer = config =>
{
previousInitializer(config);
...
};
}
GlobalConfiguration.Configure runs EnsureInitialized immediately after invoking your action:
public static void Configure(Action<HttpConfiguration> configurationCallback)
{
if (configurationCallback == null)
{
throw new ArgumentNullException("configurationCallback");
}
configurationCallback.Invoke(Configuration);
Configuration.EnsureInitialized();
}
Don't forget, if you run in to a wall, the source for asp.net is available at http://aspnetwebstack.codeplex.com/SourceControl/latest
I've had a related issue. Sometimes calling GlobalConfiguration.Configure multiple times triggers this error. As a workaround, I've put all configuration initialization logic in one place.
IF THIS ERROR SEEMS TO HAVE COME "OUT OF NOWHERE", i.e. your app was working perfectly fine for a while, ask yourself: Did I add an action to a controller or change any routes prior to seeing this error?
If the answer is yes (and it probably is), you likely made a mistake in the process. Incorrect formatting, copy/pasting an action and forgetting to make sure the endpoint names are unique, etc. will all end you up here. The suggestion that this error makes on how to resolve it can send you barking up the wrong tree.
For me, the problem was that I was trying to use named parameters for query string fields in my routes:
[Route("my-route?field={field}")]
public void MyRoute([FromUri] string field)
{
}
Query string fields are automatically mapped to parameters and aren't actually part of the route definition. This works:
[Route("my-route")]
public void MyRoute([FromUri] string field)
{
}
Although the above answer works if incase that is not set, In my case this stuff was set already. What was different was that, for one of the APIs I had written, I had prefixed the route with a / . Example
[Route("/api/abc/{client}")]
.Changing this to
[Route("api/abc/{client}")]
fixed it for me
Call
GlobalConfiguration.Configuration.MapHttpAttributeRoutes();
before
GlobalConfiguration.Configure(c => ...);
completes its execution.
I got this error when the version of Newtonsoft.Json was different in my main project compared to the helper project
One typically gets this exception when route templates in "Attribute Routing" are not proper.
For example, i got this when i wrote the following code:
[Route("{dirName:string}/contents")] //incorrect
public HttpResponseMessage GetDirContents(string dirName) { ... }
In route constraints syntax {parameter:constraint}, constraint by default is of type string. No need to mention it explicitly.
[Route("{dirName}/contents")] //correct
public HttpResponseMessage GetDirContents(string dirName) { ... }
I began getting this error one day. After I'd altered our app to call EnsureInitialized() I was able to see the root cause.
I had a custom attribute, a filter, on an action. That attribute class had had a breaking change made in the NuGet package in which it lives.
Even though I'd updated the the code and it all compiled, the local IIS worker was loading an old DLL and not finding a class member during initialization, reading attributes on actions etc.
For some reason (possibly due to order/when our logging is initialized), this error was not discoverable, possibly leaving the WebAPI in a strange state, until I'd added EnsureInitialized() which caught the exception and surfaced it.
Performing a proper bin and obj clean via a handy script resolved it.
In my case I created the webservice in project A and started it from Project B and I got exactly this error. The problem was that some .dll-files which are required by A where missing in the build-output-folder of B. Ensure that these .dll-files are available fixed it.
In my case , i used an Entity as parameter of my action that its 'Schema' is missing.
Wrong attribute:
[Table("Table name", Schema = "")]
Correct :
[Table("Table name", Schema = "schema name")]
In my case I fixed replacing:
<Route("{id:string}")>
with
<Route("{id}")>
Strange that I was sure that the original code was working before suddenly stopping, go figure....
I experienced this similar error.
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace> at System.Web.Http.Routing.RouteCollectionRoute.get_SubRoutes() at System.Web.Http.Routing.RouteCollectionRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)</StackTrace>
</Error>
After fiddling with it for a while, I realized two problems: directory name collides with routing prefix and routing prefix must not end with '/'. When starting up the service for debugging I got this browser error after adding the SampleController.cs.
The folder structure
/api/Controllers/SampleController.cs
/api/Model/...
SampleController.cs
[RoutePrefix("api/sub/{parameterId}/more/")]
public class SampleController : ApiController
{
[HttpGet]
[Route("")]
public IHttpActionResult Get(int parameterId)
{
return Ok("Knock Knock...");
}
}
Changing the routing prefix to not end in '/' and not colliding with the directory name solved the problem.

Custom AuthorizeAttribute not called

There are a lot of similar questions out there but this has me stumped.
If I used [Authorize] I get prompted for a username and password but if I use [InternalAuthorizeV2] I don't
I have a custom AuthorizeAttribute that for the moment does not do any anything special (I'm limiting things that could be wrong).
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class InternalAuthorizeV2Attribute: AuthorizeAttribute
{}
and a Action in my Controller
[InternalAuthorizeV2(Roles = "MobileApps_Parkingggg")]
public ActionResult Index()
{
var model = new VmParking();
return View(model);
}
The login is handled in a different app but they have identical web config lines
<machineKey compatibilityMode="Framework20SP2" validationKey="editedOut" decryptionKey="editedOut" validation="SHA1" decryption="AES"/>
<authentication mode="Forms">
<forms name="emLogin" loginUrl="/Login/Index" timeout="540" protection="All" path="/" enableCrossAppRedirects="true" cookieless="UseCookies" />
</authentication>
<sessionState timeout="540" />
I know that if I login by going to a page with [Authorize] then back to my trouble page I can see the username but it doesn't seem to be calling my customer attribute.
New information:
My attribute is in a shared DLL as it's used by many apps. It seems that if I copy the cs file to the web project it works. No idea why, still looking for hints or tips.
From what you've said, it all behaves fine if you use [Authorize] but not [InternalAuthorizeV2].
Your shared dll shouldn't make any difference if it is set up correctly; I have the same thing working. Make sure the web project is using the latest version of the dll and you have the right assembly references in the shared dll - System.Web.Mvc, v4.0.0.0 in my project.
You say its used by many apps? Do all apps have the same problem with the shared dll or just one of them? If it's just one, check the references for the one with the problem.
If the below tests all work then the final option is that whatever you are doing in your authorize attribute in the dll isn't picking up the right context for that app, or using the right membership provider or database - you haven't included the code you are using inside your attribute so it's hard to know if that could be causing a problem.
Test dependencies
You could try adding a base authorize attribute to your shared dll, and then implementing another authorize attribute in your web project that inherits the base attribute you just created. This should show that you have your shared dll set up correctly.
// in the dll:
public class BaseAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute { ... }
// in the web project:
public class InternalAuthorizeV2Attribute : BaseAuthorizeAttribute { ... }
If simply moving it from your dll project to the web project fixes it, the most likely issue is the web project is not using the right version of the dll (try cleaning and doing a complete rebuild) or your dll is referencing the wrong dlls for the System.Web.Mvc.AuthorizeAttribute. You say you have triple checked, but trying the above debugging should help you work out if this really is the case.
Debug authorization method calls
If that doesn't work then try adding the following override methods to a very simple attribute, and seeing if you hit the breakpoint on the call to base.OnAuthorization. If you don't, then it may not be the actual attributes causing your problem.
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method,
Inherited = true, AllowMultiple = true)]
public class InternalAuthorizeV2Attribute : System.Web.Mvc.AuthorizeAttribute {
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext) {
return false; // breakpoint here, and this should force an authorization failure
}
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext); // breakpoint here
}
}
This should completely prevent any user access to the Action. If that doesn't work then you know the issue doesn't lie in your attribute, but that your attribute is not being applied.
You can also add the following to your controller and check that it is hit before the authorize attribute:
protected override void OnAuthorization(AuthorizationContext filterContext) {
base.OnAuthorization(filterContext);
}
Authorization chaining
Note that you have your attribute attached to the Action method, so it will only be hit if a an authorization attribute earlier in the chain (e.g. a global filter or controller attribute) hasn't already prevented the user being authorized (see my answer here), or prematurely returns an ActionResult that stops the chain reaching your Action attribute. However it's unlikely this is the problem if simply moving it from the dll to the project makes it work. Similarly it's unlikely you have an AllowAnonymous in the wrong place from what you've said.

Ninject in ASP.NET MVC4

So after much screwing around I finally got Ninject wired in and compiling in my MVC4 application. The problem I was running into is the IDependencyScope interface no longer exists from what I can tell and the System.Web.Http.Dependencies namespace was done away with.
So, my problem now is I have everything wired in and upon running the application I get:
Sequence contains no elements
[InvalidOperationException: Sequence contains no elements]
System.Linq.Enumerable.Single(IEnumerable`1 source) +379
Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:53
Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:31
Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:53
Ninject.Web.Common.NinjectHttpApplication.Application_Start() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\NinjectHttpApplication.cs:81
Which I haven't been able to track down or even begin to fathom where it is coming from.
My standard Ninject methods inside the Global.asax.cs look as follows:
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IRenderHelper>().To<RenderHelper>();
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
return kernel;
}
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
BundleTable.Bundles.RegisterTemplateBundles();
}
And my custom resolver:
public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _kernel.GetAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
public void Dispose()
{
// When BeginScope returns 'this', the Dispose method must be a no-op.
}
}
Any insight here would be greatly appreciated. I've spent far too much time already trying to get any DI framework wired into the latest MVC4 RC running on .NET 4.5 and have now just reached my tolerance level for things just not working at all..
Edit #1
A little further research digging around in github the ExtensionsForIEnumerableOfT.cs doesn't help much:
https://github.com/ninject/ninject/blob/master/src/Ninject/Infrastructure/Language/ExtensionsForIEnumerableOfT.cs
And possibly if I had wrote it myself I would begin to understand this but Bootstrapper.cs doesn't help too much either.
https://github.com/ninject/Ninject.Web.Common/blob/master/src/Ninject.Web.Common/Bootstrapper.cs
Hoping these details will make it easier for any of you who might have more experience with Ninject.
Edit #2 The error encountered is specifically in NinjectMvcHttpApplicationPlugin.cs:
The offending line is:
ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
Which lives in the following method:
public void Start()
{
ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
DependencyResolver.SetResolver(this.CreateDependencyResolver());
RemoveDefaultAttributeFilterProvider();
}
The ModelValidatorProviders collection contains 2 elements:
{System.Web.Mvc.DataErrorInfoModelValidatorProvider}
{System.Web.Mvc.ClientDataTypeModelValidatorProvider}
And it's trying to remove a single instance of:
System.Web.Mvc.DataAnnotationsModelValidatorProvider
Which apparently isn't loaded up in the ModelValidationProviders.Providers collection. Any ideas from here?
Resolution to Above Exception And Onto The Next
To resolve the issue in the ModelValidatorProviders I had to manually add an object it was expecting. So now my CreateKernel method looks like:
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IRenderHelper>().To<RenderHelper>();
kernel.Unbind<IDocumentViewerAdapter>();
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
FilterProviders.Providers.Add(new FilterAttributeFilterProvider());
return kernel;
}
Now it runs and gets into the actual guts of Ninject but still has an issue, one that makes no sense yet again:
Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Suggestions:
1) Ensure that you have defined a binding for IntPtr.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Ok after beating my head against the wall for far too long I figured out what was going on. The default project type for MVC4 running on .NET 4.5 had a reference to the original RC version of System.Web.Http instead of the updated version.
Namespaces were missing, objects didn't exist, life was not good.
Steps for resolution:
Remove your reference to System.Web.Http in your MVC4 project
Add Reference -> System.Web.Http
Delete all work arounds you put in to get the old garbage version of System.Web.Http to work
Reapply standard process to wire in Ninject.
HOWEVER, the error of:
Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
1) Request for IHttpModule
Suggestions:
1) Ensure that you have defined a binding for IntPtr.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
Update This was solved by updating MVC from MVC4 Beta to MVC4 RC.
Check out the Pro ASP.NET MVC 3 book. I just ported this code over from MVC3 to MVC4 last night and works correctly. Page 322 to be exact.
What I don't see is where you are mapping your Interface to your concrete items.
Bind<ISomething>().To<Something>();
Add another constructor and add the method that calls your mapping;
public NinjectDependencyResolver() {
_kernal = new StandardKernel();
RegisterServices(_kernel);
}
public static void RegisterServices(IKernel kernel) {
kernel.Bind<ISomething>().To<Something>();
}
Here's what a resolver could/should look like;
public class NinjectDependencyResolver : IDependencyResolver {
private IKernal _kernel;
public NinjectDependencyResolver(){
_kernal = StandardKernal();
AddBindings();
}
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernal.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>() {
return _kernal.Bind<T>();
}
public static void RegisterServices(IKernel kernel){
//Add your bindings here.
//This is static as you can use it for WebApi by passing it the IKernel
}
}
Global.Asx -
Application_Start()
method
DependencyResolver.SetResolver(new NinjectDependencyResolver());
That's it.
UPDATED 11/14/2012
On a side note, if you're working with MVC WebAPI, you will want to use WebApiContrib.IoC.Ninject from nuget. Also, check out the "Contact Manager" in their samples asp.net.com. This helped to cleanup the implementation of Ninject
Just delete NinjectWebCommon.cs file from your project (it is in App_Start folder). and everything should be working.
Source: http://mlindev.blogspot.com.au/2012/09/how-to-implement-dependency-injection.html
When you will install latest Ninject.MVC3 from NuGet package we find following code on top of the NinjectWebCommon.cs file:
[assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]
in this case we dont need to register ninject explicitly in global.asax
I found a good content on using Ninject with MVC 4 here
I tend to keep my Ninject bootstrapping in a separate project. In order to use the .InRequestScope() extension method of IBindingInSyntax<T>, I had added via Nuget the Ninject.Web.Common library. Alas, this library includes the app_start bootstrapper, resulting in duplicate NinjectWebCommon classes and attachment via WebActivator (1 in said project and 1 in the MVC project itself).
I deleted the duplicate App_Start folder from my bootstrap project, and this solved it.
I have come across the same issue not quite sure what has fixed after below changes
added Ninject.MVC4 to project
deleted NinjectWebCommon.cs (the generated file, as the integration already exists in global.ascx.cs file)
I am using DD4T, and encountered same error.
After confirming that all packages are installed by nuget package manager,
I found that some of the DLLs/references were missing (newtonsoft etc):
Then, after re-installing Newtonsoft.Json (to re-install package use following command in Nuget Package Manager:Update-Package –reinstall Newtonsoft.Json), and putting netrtsn.dll from Tridion Deployer bin, I got this error - "Sequence contains no elements" with exactly same stack trace as given in this question.
Thanks to Naga, for providing this resolution
deleted NinjectWebCommon.cs (the generated file, as the integration already exists in global.ascx.cs file), and wohooooo!!!! all errors resolved, Tridion + MVC4 = DD4T is running fine now.
I have also had this problem when I used nuget to install Ninject.MVC4 in a project referenced by my actual MVC website project.
The trouble is that the NinjectWebCommon.cs file automatically installed in the App_Start directory of the referenced project conflicts with the (actual, useful) one installed in my website project. Removing the NinjectWebCommon.cs file from the referenced project resolves the error.

Categories

Resources