I have an interface with a method marked with the obsolete attribute. The attributes error parameter is set to true to throw an exception when used. The problem is this causes the stub to not generate for the whole class. When I alter the value to false the stub generates as expected.
I’m looking for a way to generate the stub while retaining the error parameter as true.
public interface ICar
{
void Start();
[Obsolete("this is obsolete Stop, stop using it", true)]
void Stop();
}
I’ve tried different permutations of.
<Moles xmlns="http://schemas.microsoft.com/moles/2010/">
<Assembly Name="My.Car.Services"/>
<StubGeneration>
<TypeFilter TypeName="ICar" SkipObsolete="true" />
</StubGeneration>
</Moles>
This is by design. When a method is marked at Obsolete(..., true), C# will not allow to instantiate an class implementing that interface.
Related
In my submodule, I have:
public class CustomerRepository : ICustomerRepository
{
private readonly IDBEngine _dbEngine;
[CanBeNull] private readonly string _overriddenDebugEmail;
[Obsolete("Use the other constructor")]
public CustomerRepository(IDBEngine dbEngine)
{
_dbEngine = dbEngine;
_overriddenDebugEmail = null;
}
// ReSharper disable once UnusedMember.Global
public CustomerRepository(IDBEngine dbEngine, IDebugConstants debugConstants)
{
_dbEngine = dbEngine;
_overriddenDebugEmail = debugConstants.OverridingDebugEmail;
}
...
The problem is, when I simply update the submodule without implementing IDebugConstants, I get the following runtime error:
Error activating IDebugConstants
No matching bindings are available, and the type is not self-bindable.
I want Ninject to bind to the Obsolete constructor if IDebugConstants is not implemented. But it refuses to because of the obsolete attribute.
In theory I could remove the Obsolete attribute, but I want it to show that that code should no longer exist once all old programs using the submodule have been updated.
Is there some way to make Ninject ignore the Obsolete attribute?
Or am I going about this entirely wrong somehow?
You can do this by adding the [Inject] attribute to your [Obsolete] constructor.
The reason for this is how the constructor scoring is implemented. Specifically this section of the Score method:
if (directive.Constructor.HasAttribute(this.settings.InjectAttribute))
{
return int.MaxValue;
}
if (directive.Constructor.HasAttribute(typeof(ObsoleteAttribute)))
{
return int.MinValue;
}
You will see that if the constructor has the [Obsolete] attribute then it is given the minimum possible score. But prior to that, if the constructor has the [Inject] attribute then it will be given the highest possible score.
This doesn't help in the specific case you mentioned where you want a conditional binding when IDebugConstants is not implemented, but it does answer "Is there some way to make Ninject ignore the Obsolete attribute?"
In other DI containers, I have observed TryAddScoped, TryAddTransient, TryAddSingleton etc.
The idea behind Try is to avoid registering multiple times. If a service is already registered, then using Try will not attempt to register again I guess.
With inject
Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
So is there any Try equivalent in Ninject?
There's no simple equivalent.
Performing
Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
will result in in an exception when resolving a IHttpContextAccessor, and when resolving IEnumerable<IHttpContextAccessor> it will return two HttpContextAccessor instances.
However, you can write your own "Try":
Checking whether Binding already exists
if(!Kernel.GetBindings(typeof(IHttpContextAccessor)).Any())
{
Kernel.Bind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
}
Of course you can also write your own extension method for that:
public static class NinjectBindingExtensions
{
public static void TryBind<T>(
this IKernel kernel,
Action<IBindingToSyntax<T>> configureBinding)
{
if (!kernel.GetBindings(typeof(T)).Any())
{
configureBinding(kernel.Bind<T>());
}
}
}
Rebind
One way to work around the issue is to use .Rebind instead of .Bind. If there's no pre-existing binding it will work just like .Bind. And if there's a pre-existing binding, it will replace it. Thus:
Kernel.Rebind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
Kernel.Rebind<IHttpContextAccessor>().To<HttpContextAccessor>().InSingletonScope();
Resolving IHttpContextAccessor will result in one instance of HttpContextAccessor.
Preventing Duplicate Module Loading
In case the problem is not with multiple components / NinjectModules creating bindings for the same type, but rather with loading the same NinjectModule twice, you can can prevent duplicate loading by:
if(!Kernel.HasModule(typeof(MyModule)))
{
Kernel.Load<MyModule>();
}
I am using the new Test Doubles in EF6 as outlined here from MSDN . VS2013 with Moq & nUnit.
All was good until I had to do something like this:
var myFoo = context.Foos.Find(id);
and then:
myFoo.Name = "Bar";
and then :
context.Entry(myFoo).Property("Name").IsModified = true;
At this point is where I get an error:
Additional information: Member 'IsModified' cannot be called for
property 'Name' because the entity of type
'Foo' does not exist in the context. To add an
entity to the context call the Add or Attach method of
DbSet.
Although, When I examine the 'Foos' in the context with an AddWatch I can see all items I Add'ed before running the test. So they are there.
I have created the FakeDbSet (or TestDbSet) from the article. I am putting each FakeDbSet in the FakeContext at the constructor where each one gets initialized. Like this:
Foos = new FakeDbSet<Foo>();
My question is, is it possible to work with the FakeDbSet and the FakeContext with the test doubles scenario in such a way to have access to DbEntityEntry and DBPropertyEntry from the test double? Thanks!
I can see all items I Add'ed before running the test. So they are there.
Effectively, you've only added items to an ObservableCollection. The context.Entry method reaches much deeper than that. It requires a change tracker to be actively involved in adding, modifying and removing entities. If you want to mock this change tracker, the ObjectStateManager (ignoring the fact that it's not designed to be mocked at all), good luck! It's got over 4000 lines of code.
Frankly, I don't understand all these blogs and articles about mocking EF. Only the numerous differences between LINQ to objects and LINQ to entites should be enough to discourage it. These mock contexts and DbSets build an entirely new universe that's a source of bugs in itself. I've decided to do integrations test only when and wherever EF is involved in my code. A working end-to-end test gives me a solid feeling that things are OK. A unit test (faking EF) doesn't. (Others do, don't get me wrong).
But let's assume you'd still like to venture into mocking DbContext.Entry<T>. Too bad, impossible.
The method is not virtual
It returns a DbEntityEntry<T>, a class with an internal constructor, that is a wrapper around an InternalEntityEntry, which is an internal class. And, by the way, DbEntityEntry doesn't implement an interface.
So, to answer your question
is it possible to (...) have access to DbEntityEntry and DBPropertyEntry from the test double?
No, EF's mocking hooks are only very superficial, you'll never even come close to how EF really works.
Just abstract it. If you are working against an interface, when creating your own doubles, put the modified stuff in a seperate method. My interface and implementation (generated by EF, but I altered the template) look like this:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Model
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public interface IOmt
{
DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
int SaveChanges();
void SetModified(object entity);
void SetAdded(object entity);
}
public partial class Omt : DbContext, IOmt
{
public Omt()
: base("name=Omt")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<DatabaseOmtObjectWhatever> DatabaseOmtObjectWhatever { get; set; }
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
public void SetAdded(object entity)
{
Entry(entity).State = EntityState.Added;
}
}
}
I have a service that takes a dependency on HttpContextBase.
Ninject is injecting this for me already as it's set up in the MvcModule to return new HttpContextWrapper(HttpContext.Current) when HttpContextBase is requested
I want to use this service in Application_AuthenticateRequest, so i'm using property injection so that Ninject resolves it for me
When I try and access Request.UserHostAddress on the HttpContextBase I get a Value does not fall within the expected range exception
If I call HttpContext.Current.Request.UserHostAddress directly it works without problems
ExampleService.cs
public class ExampleService : IExampleService {
HttpContextBase _contextBase;
public ExampleService(HttpContextBase contextBase) {
_contextBase = contextBase;
}
public void DoSomething() {
var ip = HttpContext.Current.Request.UserHostAddress; <== this works
ip = _contextBase.Request.UserHostAddress; <== this fails
}
}
Global.asax
[Inject]
public IExampleService ExampleService { get; set; }
public void Application_AuthenticateRequest() {
ExampleService.DoSomething();
}
I'm missing something here, but I can't see what
Dependencies that are injected into classes live as long as the the class they get injected into, because the class holds a reference to them. This means that in general you should prevent injecting dependencies that are configured with a lifetime that is shorter than the containing class, since otherwise their lifetime is 'promoted' which can cause all sorts of (often hard to track) bugs.
In the case of an ASP.NET application, there is always just one HttpApplication instance that lives as long as the AppDomain lives. So what happens here is that the injected ExampleService gets promoted to one-per-appdomain (or singleton) and since the ExampleService sticks around, so does its dependency, the HttpContextBase.
The problem here of course is that an HTTP context -per definition- can't outlive a HTTP request. So you're storing a single HttpContextBase once, but it gets reused for all other requests. Fortunately ASP.NET throws an exception, otherwise you would probably be in much more trouble. Unfortunately the exception isn't very expressive. They could have done better in this case.
The solution is to not inject dependencies in your HttpApplication / MvcApplication. Ever! Although it's fine to do so when you're injecting singletons that only depend on singletons recursively, it is easy to do this wrong, and there's no verification mechanism in Ninject that signals you about this error.
Instead, always resolve IExampleService on each call to AuthenticateRequest. This ensures that you get an ExampleService with the right lifetime (hopefully configured as per-web-request or shorter) and prevents this kind of error. You can either call into the DependencyResolver class to fetch an IExampleService or call directly into the Ninject Kernel. Calling into the Kernel is fine, since the Application_AuthenticateRequest can be considered part of the Composition Root:
public void Application_AuthenticateRequest() {
var service = DependencyResolver.Current.GetService<IExampleService>();
service.DoSomething();
}
I have an Aspect that implements INotifyPropertyChanged on a class. The aspect includes the following:
[OnLocationSetValueAdvice, MethodPointcut("SelectProperties")]
public void OnPropertySet(LocationInterceptionArgs args)
{
var currentValue = args.GetCurrentValue();
bool alreadyEqual = (currentValue == args.Value);
// Call the setter
args.ProceedSetValue();
// Invoke method OnPropertyChanged (ours, the base one, or the overridden one).
if (!alreadyEqual)
OnPropertyChangedMethod.Invoke(args.Location.Name);
}
This works fine when I instantiate the class normally, but I run into problems when I deserialize the class using a DataContractSerializer. This bypasses the constructor, which I'm guessing interferes with the way that PostSharp sets itself up. This ends up causing a NullReferenceException in an intercepted property setter, but before it has called the custom OnPropertySet, so I'm guessing it interferes with setting up the LocationInterceptionArgs.
Has anyone else encountered this problem? Is there a way I can work around it?
I did some more research and discovered I can fix the issue by doing this:
[OnDeserializing]
private void OnDeserializing(StreamingContext context)
{
AspectUtilities.InitializeCurrentAspects();
}
I thought, okay, that's not too bad, so I tried to do this in my Aspect:
private IEnumerable<MethodInfo> SelectDeserializing(Type type)
{
return
type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(
t => t.IsDefined(typeof (OnDeserializingAttribute), false));
}
[OnMethodEntryAdvice, MethodPointcut("SelectDeserializing")]
public void OnMethodEntry(MethodExecutionArgs args)
{
AspectUtilities.InitializeCurrentAspects();
}
Unfortunately, even though it intercepts the method properly, it doesn't work. I'm thinking the call to InitializeCurrentAspects isn't getting transformed properly, since it's now inside the Aspect rather than directly inside the aspect-enhanced class. Is there a way I can cleanly automate this so that I don't have to worry about calling this on every class that I want to have the Aspect?
Support for serialization has been added lately and is available as a hotfix.
http://www.sharpcrafters.com/downloads/postsharp-2.0/hot-fixes