StructureMap Exception Code 205 Missing requested Instance property - structuremap

I'm trying out the latest build of StructureMap, to learn about IoC containers and the like. As my first test, I have the following class:
public class Hospital
{
private Person Person { get; set; }
private int Level { get; set; }
public Hospital(Person employee, int level)
{
Person = employee;
Level = level;
}
public void ShowId()
{
Console.WriteLine(this.Level);
this.Person.Identify();
}
}
I then use StructureMap like this:
static void Main()
{
ObjectFactory.Configure(x =>
{
x.For<Person>().Use<Doctor>();
x.ForConcreteType<Hospital>().Configure.Ctor<int>().Equals(23);
});
var h = ObjectFactory.GetInstance<Hospital>();
h.ShowId();
}
So I'm passing a Doctor object as the first constructor param to Hospital, and I'm trying to set the level param to 23. When I run the above code I get:
Unhandled Exception:
StructureMap.StructureMapException:
StructureMap Exception Code: 205
Missing requested Instance property
"level" for InstanceKey
"5f8c4b74-a398-43f7-
91d5-cfefcdf120cf"
So it looks like I'm not setting the level param at all. Can someone point me in the right direction - how do I set the level param in the constructor?
Cheers.
Jas.

You were very close. You accidentially used the System.Object.Equals method on the dependency expression rather than the Is Method. I would also recommend when configuring common types like string or value types (int, DateTime) to specify the constructor argument name to avoid ambiguity.
Here is my test with what you are looking for:
[TestFixture]
public class configuring_concrete_types
{
[Test]
public void should_set_the_configured_ctor_value_type()
{
const int level = 23;
var container = new Container(x =>
{
x.For<Person>().Use<Doctor>();
x.ForConcreteType<Hospital>().Configure.Ctor<int>("level").Is(level);
});
var hospital = container.GetInstance<Hospital>();
hospital.Level.ShouldEqual(level);
}
}

Related

OptionsModel dependency injection in vNext console application

I have a vNext console application where one of my classes takes the OptionsModel<T> POCO configuration settings class.
I am unable to get the POCO settings class resolved and injected into my RabbitMqConnection class below.
Setting up the ServiceProvider is not the issue, it's the resolution of the settings class.
Note, this is a vNext console application (not an mvc6 app).
My second question is, and I understand constructor arguments should be kept minimal, but is it not best to pass the two strings as constructor arguments rather than an IOptions class as the former method is more descriptive of what the RabbitMqConnection class requires? If so, how is this best injected from the class that defined the mappings (Program.cs file in example below)
public class RabbitMqConnection
{
public string HostName { get; set; }
public string UserName { get; set; }
public RabbitMqConnection(IOptions<MessagingSettings> settings)
{
HostName = settings.Value.HostName;
UserName = settings.Value.UserName;
}
}
public class MessagingSettings
{
public string HostName { get; set; }
public string UserName { get; set; }
}
appsettings.json
{
"MessagingSettings":{
"HostName":"localhost",
"Username":"guest"
}
}
public void ConfigureServices(IServiceCollection services)
{
// tried registration a number of ways as below
services.Configure<MessagingSettings>(Configuration.GetSection("MessagingSettings"));
services.Configure<MessagingSettings>(Configuration);
// attempt 1 - get runtime error saying cant resolve IOptions<MessageSettings>
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection, RabbitMqConnection>());
// attempt 2 - same as above, when i breakpoint on messagingSettings, all the values in the object are null
services.TryAdd(ServiceDescriptor.Singleton<RabbitMqConnection>(factory =>
{
// instead of injecting the MessageSettings, pass through the string values (constructor omitted for clarity)
var messagingSettings = Configuration.Get<MessagingSettings>();
return new RabbitMqConnection(messagingSettings.HostName, messagingSettings.UserName);
}));
}
var conn = ServiceProvider.GetRequiredService<RabbitMqConnection>();
You need to call services.AddOptions()

EF 4: Referencing Non-Scalar Variables Not Supported

I'm using code first and trying to do a simple query, on a List property to see if it contains a string in the filtering list. However I am running into problems. For simplicity assume the following.
public class Person
{
public List<string> FavoriteColors { get; set; }
}
//Now some code. Create and add to DbContext
var person = new Person{ FavoriteColors = new List<string>{ "Green", "Blue"} };
dbContext.Persons.Add(person);
myDataBaseContext.SaveChanges();
//Build
var filterBy = new List<string>{ "Purple", "Green" };
var matches = dbContext.Persons.AsQueryable();
matches = from p in matches
from color in p.FavoriteColors
where filterBy.Contains(color)
select p;
The option I am considering is transforming this to a json serialized string since I can perform a Contains call if FavoriteColors is a string. Alternatively, I can go overboard and create a "Color" entity but thats fairly heavy weight. Unfortunately enums are also not supported.
I think the problem is not the collection, but the reference to matches.
var matches = dbContext.Persons.AsQueryable();
matches = from p in matches
from color in p.FavoriteColors
where filterBy.Contains(color)
select p;
If you check out the Known Issues and Considerations for EF4 this is more or less exactly the case mentioned.
Referencing a non-scalar variables,
such as an entity, in a query is not
supported. When such a query executes,
a NotSupportedException exception is
thrown with a message that states
"Unable to create a constant value of
type EntityType.
Also note that it specifically says that referencing a collection of scalar variables is supported (that's new in EF 4 imo).
Having said that the following should work (can't try it out right now):
matches = from p in dbContext.Persons
from color in p.FavoriteColors
where filterBy.Contains(color)
select p;
I decided to experiment by creating a "StringEntity" class to overcome this limitation, and used implicit operators to make nice easy transformations to and from strings. See below for solution:
public class MyClass
{
[Key, DatabaseGenerated(DatabaseGenerationOption.Identity)]
public Guid Id { get; set; }
public List<StringEntity> Animals { get; set; }
public MyClass()
{
List<StringEntity> Animals = List<StringEntity>();
}
}
public class StringEntity
{
[Key, DatabaseGenerated(DatabaseGenerationOption.Identity)]
public Guid Id { get; set; }
public string Value { get; set; }
public StringEntity(string value) { Value = value; }
public static implicit operator string(StringEntity se) { return se.Value; }
public static implicit operator StringEntity(string value) { return new StringEntity(value); }
}
public class MyDbContext : DbContext
{
public DbSet<MyClass> MyClasses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyClass>()
.HasMany(x => x.Animals)
.WithMany()
.Map(x =>
{
x.MapLeftKey(l => l.Id, "MyClassId");
x.MapRightKey(r => r.Id, "StringEntityId");
});
}
}
...Everything looked like it was working perfectly with some testing(Albeit heavy), and then I implemented for its original purpose, a Multiselect ListBox in an MVC3 view. For reasons unknown to me, IF the ListBox is assigned the same NAME as an Entity Collection Property, none of your selected items will be loaded.
To demonstrate the following did NOT work:
//Razor View Code
string[] animalOptions = new string[] {"Dog", "Cat", "Goat"};
string[] animalSelections = new string[] {"Dog", "Cat"};
Html.ListBox("Animals", Multiselect(animalOptions, animalSelections));
To get around this limitation, I needed to do four things:
//#1 Unpluralize the ListBox name so that is doesn't match the name Model.Animals
var animalOptions = new string[] {"Dog", "Cat", "Goat"};
#Html.ListBox("Animal", new MultiSelectList(animalOptions, Model.Animals.Select(x => x.Value)))
//#2 Use JQuery to replace the id and name attribute, so that binding can occur on the form post
<script type="text/javascript">
jQuery(function ($) {
$("select#Animal").attr("name", "Animals").attr("id", "Animals");
});
</script>
//#3 Create a model binder class to handle List<StringEntity> objects
public class StringEntityListBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var stringArray = controllerContext.HttpContext.Request.Params.GetValues(bindingContext.ModelName);
return stringArray.Select(x => new StringEntity(x)).ToList();
}
}
//#4 Initialize the binder in your Global.asax setup.
ModelBinders.Binders.Add(typeof(List<StringEntity>), new StringEntityListBinder ());
Note, that the Listbox bug did NOT occur when the property was a List of strings, it just didn't like it when it was a List of entities.

S#arp Architecture Fluent mapping for self referencing entity (Tree structure)

I've come up against a problem in converting my Fluent NH mapping to Sharp Architecture. I like the platform for it's ease, however it seems to handle entity mappings slightly differently to pure Fluent NH.
I have a Entity 'Category' that is a simple tree structure. I have to override the auto-mapping as there is a M:M property that I need to add in (not included in code below).
When I create tests on the repository, the GetAll method returns all Categories as it should, however the Children property just infinitely loops itself. i.e. the list of children for each category only contains itself, in and unending loop.
/// The Entity ///
public class Category : Entity
{
public Category()
{
InitMembers();
}
/// <summary>
/// Creates valid domain object
/// </summary>
public Category(string name)
: this()
{
Name = name;
}
/// <summary>
/// Creates valid domain object
/// </summary>
public Category(string name, int depth)
: this()
{
Name = name;
Depth = depth;
}
private void InitMembers()
{
Children = new List<Category>();
}
[DomainSignature]
[NotNullNotEmpty]
public virtual string Name { get; protected set; }
[DomainSignature]
public virtual int Depth { get; protected set; }
public virtual Category Parent { get; set; }
public virtual IList<Category> Children { get; private set; }
public virtual void AddChild(Category category)
{
category.Parent = this;
Children.Add(category);
}
}
/// The Mapping ///
public class CategoryMap : IAutoMappingOverride<Category>
{
public void Override(AutoMap<Category> mapping)
{
mapping.Id(x => x.Id, "CategoryId")
.WithUnsavedValue(0)
.GeneratedBy.Identity();
mapping.Map(x => x.Name).WithLengthOf(50);
mapping.Map(x => x.Depth);
mapping.HasMany<Category>(x => x.Children)
.Inverse()
.Cascade.All()
.KeyColumnNames.Add("Parent_id")
.AsBag();
}
}
/// The Data Repository Tests ///
[TestFixture]
[Category("DB Tests")]
public class CategoryRepositoryTests : RepositoryTestsBase
{
private readonly IRepository<Category> _repository = new Repository<Category>();
protected override void LoadTestData()
{
CreatePersistedCategory("Root 1");
CreatePersistedCategory("Root 2");
CreatePersistedCategoryWithChildren("Level 1", "Level 2", "Level 3");
}
[Test]
public void CanGetAllCategories()
{
var categories = _repository.GetAll();
categories.ShouldNotBeNull();
categories.Count.ShouldEqual(5);
}
[Test]
public void CanGetCategoryById()
{
var category = _repository.Get(1);
category.Name.ShouldEqual("Root 1");
category.Depth.ShouldEqual(1);
}
[Test]
public void CanGetCategoryChildren()
{
var category = _repository.Get(3);
category.Name.ShouldEqual("Level 1");
category.Depth.ShouldEqual(1);
category.Children.ShouldNotBeNull();
category.Children.Count.ShouldEqual(1);
category.Children[0].Name.ShouldEqual("Level 2");
category.Children[0].Depth.ShouldEqual(2);
category.Children[0].Children.ShouldNotBeNull();
category.Children[0].Children.Count.ShouldEqual(1);
category.Children[0].Children[0].Name.ShouldEqual("Level 3");
category.Children[0].Children[0].Depth.ShouldEqual(3);
}
private void CreatePersistedCategory(string categoryName)
{
var category = new Category(categoryName, 1);
_repository.SaveOrUpdate(category);
FlushSessionAndEvict(category);
}
private void CreatePersistedCategoryWithChildren(string category1, string category2, string category3)
{
var cat1 = new Category(category1, 1);
var cat2 = new Category(category2, 2) { Parent = cat1 };
var cat3 = new Category(category3, 3) { Parent = cat2 };
cat1.AddChild(cat2);
cat2.AddChild(cat3);
_repository.SaveOrUpdate(cat1);
FlushSessionAndEvict(cat1);
}
}
Managed to work it out, after much Mapping tweaking. The Auto-mapping stuff although very cool requires some understanding. RTFM for me...
Right you are, I hadn't yet discovered or understood the Auto-mapping conventions: TableNameConvention, PrimaryKeyConvention, and specifically HasManyConvention. The default S#arp code likes to pluralise its database tables, and have Id columns with the table name prefixed, i.e. CategoryId.
I don't like to pluralise, and I like consistent Id columns, 'Id' suffices. And my foreign key references were different style to, I like Category_id.
public class HasManyConvention : IHasManyConvention
{
public bool Accept(IOneToManyCollectionInstance oneToManyPart)
{
return true;
}
public void Apply(IOneToManyCollectionInstance oneToManyPart)
{
oneToManyPart.KeyColumnNames.Add(oneToManyPart.EntityType.Name + "_id");
}
}
public class PrimaryKeyConvention : IIdConvention
{
public bool Accept(IIdentityInstance id)
{
return true;
}
public void Apply(IIdentityInstance id)
{
id.Column("Id");
}
}
However now this all works a treat but I now have a problem with Many-to-many mappings. It seems S#arp doesn't quite support them yet. My mapping overrides don't seem to work, nothing gets inserted into my mapping table in the database.
See: S#arp Architecture many-to-many mapping overrides not working
I was not able to solve this using fluent conventions and from what I have seen searching around this currently can't be done using conventions. Fluent assumes that a self-referencing tree like this is many-to-many, so in your case I assume you are trying to map a many-to-many relationship and so there should be no problem.
In my case I needed to map it as many-to-one (for a strict hierarchy of nested comments and replies). The only way I could figure out to do this was setting an override for the parent-child class to map that relationship. Fortunately it is very easy.
I would love to know if there is a way to successfully map many-to-one like this with conventions though.

Mocking a DataServiceQuery<TElement>

How can I mock a DataServiceQuery for unit testing purpose?
Long Details follow:
Imagine an ASP.NET MVC application, where the controller talks to an ADO.NET DataService that encapsulates the storage of our models (for example sake we'll be reading a list of Customers). With a reference to the service, we get a generated class inheriting from DataServiceContext:
namespace Sample.Services
{
public partial class MyDataContext : global::System.Data.Services.Client.DataServiceContext
{
public MyDataContext(global::System.Uri serviceRoot) : base(serviceRoot) { /* ... */ }
public global::System.Data.Services.Client.DataServiceQuery<Customer> Customers
{
get
{
if((this._Customers==null))
{
this._Customers = base.CreateQuery<Customer>("Customers");
}
return this._Customers;
}
}
/* and many more members */
}
}
The Controller could be:
namespace Sample.Controllers
{
public class CustomerController : Controller
{
private IMyDataContext context;
public CustomerController(IMyDataContext context)
{
this.context=context;
}
public ActionResult Index() { return View(context.Customers); }
}
}
As you can see, I used a constructor that accepts an IMyDataContext instance so that we can use a mock in our unit test:
[TestFixture]
public class TestCustomerController
{
[Test]
public void Test_Index()
{
MockContext mockContext = new MockContext();
CustomerController controller = new CustomerController(mockContext);
var customersToReturn = new List<Customer>
{
new Customer{ Id=1, Name="Fred" },
new Customer{ Id=2, Name="Wilma" }
};
mockContext.CustomersToReturn = customersToReturn;
var result = controller.Index() as ViewResult;
var models = result.ViewData.Model;
//Now we have to compare the Customers in models with those in customersToReturn,
//Maybe by loopping over them?
foreach(Customer c in models) //*** LINE A ***
{
//TODO: compare with the Customer in the same position from customersToreturn
}
}
}
MockContext and MyDataContext need to implement the same interface IMyDataContext:
namespace Sample.Services
{
public interface IMyDataContext
{
DataServiceQuery<Customer> Customers { get; }
/* and more */
}
}
However, when we try and implement the MockContext class, we run into problems due to the nature of DataServiceQuery (which, to be clear, we're using in the IMyDataContext interface simply because that's the data type we found in the auto-generated MyDataContext class that we started with). If we try to write:
public class MockContext : IMyDataContext
{
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers { get { /* ??? */ } }
}
In the Customers getter we'd like to instantiate a DataServiceQuery instance, populate it with the Customers in CustomersToReturn, and return it. The problems I run into:
1~ DataServiceQuery has no public constructor; to instantiate one you should call CreateQuery on a DataServiceContext; see MSDN
2~ If I make the MockContext inherit from DataServiceContext as well, and call CreateQuery to get a DataServiceQuery to use, the service and query have to be tied to a valid URI and, when I try to iterate or access the objects in the query, it will try and execute against that URI. In other words, if I change the MockContext as such:
namespace Sample.Tests.Controllers.Mocks
{
public class MockContext : DataServiceContext, IMyDataContext
{
public MockContext() :base(new Uri("http://www.contoso.com")) { }
public IList<Customer> CustomersToReturn { set; private get; }
public DataServiceQuery<Customer> Customers
{
get
{
var query = CreateQuery<Customer>("Customers");
query.Concat(CustomersToReturn.AsEnumerable<Customer>());
return query;
}
}
}
}
Then, in the unit test, we get an error on the line marked as LINE A, because http://www.contoso.com doesn't host our service. The same error is triggered even if LINE A tries to get the number of elements in models.
Thanks in advance.
I solved this by creating an interface IDataServiceQuery with two implementations:
DataServiceQueryWrapper
MockDataServiceQuery
I then use IDataServiceQuery wherever I would have previously used a DataServiceQuery.
public interface IDataServiceQuery<TElement> : IQueryable<TElement>, IEnumerable<TElement>, IQueryable, IEnumerable
{
IDataServiceQuery<TElement> Expand(string path);
IDataServiceQuery<TElement> IncludeTotalCount();
IDataServiceQuery<TElement> AddQueryOption(string name, object value);
}
The DataServiceQueryWrapper takes a DataServiceQuery in it's constructor and then delegates all functionality to the query passed in. Similarly, the MockDataServiceQuery takes an IQueryable and delegates everything it can to the query.
For the mock IDataServiceQuery methods, I currently just return this, though you could do something to mock the functionality if you want to.
For example:
// (in DataServiceQueryWrapper.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return new DataServiceQueryWrapper<TElement>(_query.Expand(path));
}
// (in MockDataServiceQuery.cs)
public IDataServiceQuery<TElement> Expand(string path)
{
return this;
}
[Disclaimer - I work at Typemock]
Have you considered using a mocking framework?
You can use Typemock Isolator to create a fake instance of DataServiceQuery:
var fake = Isolate.Fake.Instance<DataServiceQuery>();
And you can create a similar fake DataServiceContext and set it's behavior instead of trying to inherit it.

Ninject - how and when to inject

I'm a newbie when it comes to DI and ninject and I'm struggling a bit
about when the actual injection should happen and how to start the
binding.
I'm using it already in my web application and it working fine there,
but now I want to use injection in a class library.
Say I have a class like this:
public class TestClass
{
[Inject]
public IRoleRepository RoleRepository { get; set; }
[Inject]
public ISiteRepository SiteRepository { get; set; }
[Inject]
public IUserRepository UserRepository { get; set; }
private readonly string _fileName;
public TestClass(string fileName)
{
_fileName = fileName;
}
public void ImportData()
{
var user = UserRepository.GetByUserName("myname");
var role = RoleRepository.GetByRoleName("myname");
var site = SiteRepository.GetByID(15);
// Use file etc
}
}
I want to use property injection here because I need to pass in a
filename in my constructor. Am I correct in saying that if I need to
pass in a constructor parameter, I cannot use constructor injection?
If I can use constructor injection with additional parameters, how do
I pass those parameters in?
I have a console app that consumes by Test class that looks as
follows:
class Program
{
static void Main(string[] args)
{
// NinjectRepositoryModule Binds my IRoleRepository etc to concrete
// types and works fine as I'm using it in my web app without any
// problems
IKernel kernel = new StandardKernel(new NinjectRepositoryModule());
var test = new TestClass("filename");
test.ImportData();
}
}
My problem is that when I call test.ImportData() my repositories are null - nothing has been injected into them. I have tried creating another module and calling
Bind<TestClass>().ToSelf();
as I thought this might resolve all injection properties in TestClass but I'm getting nowhere.
I'm sure this is a trivial problem, but I just can't seem to find out
how to go about this.
You are directly newing TestClass, which Ninject has no way of intercepting - remember there's no magic like code transformation intercepting your news etc.
You should be doing kernel.Get<TestClass> instead.
Failing that, you can inject it after you new it with a kernel.Inject( test);
I think there's an article in the wiki that talks about Inject vs Get etc.
Note that in general, direct Get or Inject calls are a Doing It Wrong smell of Service Location, which is an antipattern. In the case of your web app, the NinjectHttpModule and PageBase are the hook that intercepts object creation - there are similar interceptors / logical places to intercept in other styles of app.
Re your Bind<TestClass>().ToSelf(), generally a StandardKernel has ImplicitSelfBinding = true which would make that unnecessary (unless you want to influence its Scope to be something other than .InTransientScope()).
A final style point:- you're using property injection. There are rarely good reasons for this, so you should be using constructor injection instead.
And do go buy Dependency Injection in .NET by #Mark Seemann, who has stacks of excellent posts around here which cover lots of important but subtle considerations in and around the Dependency Injection area.
OK,
I've found out how to do what I need, thanks in part to your comments Ruben. I've created a new module that basically holds the configuration that I use in the class library. Within this module I can either Bind using a placeholder Interface or I can add a constructor parameter to the CustomerLoader.
Below is the code from a dummy console app to demonstrating both ways.
This might help someone else getting started with Ninject!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Core;
using Ninject.Core.Behavior;
namespace NinjectTest
{
public class Program
{
public static void Main(string[] args)
{
var kernel = new StandardKernel(new RepositoryModule(), new ProgramModule());
var loader = kernel.Get<CustomerLoader>();
loader.LoadCustomer();
Console.ReadKey();
}
}
public class ProgramModule : StandardModule
{
public override void Load()
{
// To get ninject to add the constructor parameter uncomment the line below
//Bind<CustomerLoader>().ToSelf().WithArgument("fileName", "string argument file name");
Bind<LiveFileName>().To<LiveFileName>();
}
}
public class RepositoryModule : StandardModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>().Using<SingletonBehavior>();
}
}
public interface IFileNameContainer
{
string FileName { get; }
}
public class LiveFileName : IFileNameContainer
{
public string FileName
{
get { return "live file name"; }
}
}
public class CustomerLoader
{
[Inject]
public ICustomerRepository CustomerRepository { get; set; }
private string _fileName;
// To get ninject to add the constructor parameter uncomment the line below
//public CustomerLoader(string fileName)
//{
// _fileName = fileName;
//}
public CustomerLoader(IFileNameContainer fileNameContainer)
{
_fileName = fileNameContainer.FileName;
}
public void LoadCustomer()
{
Customer c = CustomerRepository.GetCustomer();
Console.WriteLine(string.Format("Name:{0}\nAge:{1}\nFile name is:{2}", c.Name, c.Age, _fileName));
}
}
public interface ICustomerRepository
{
Customer GetCustomer();
}
public class CustomerRepository : ICustomerRepository
{
public Customer GetCustomer()
{
return new Customer() { Name = "Ciaran", Age = 29 };
}
}
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
}

Resources