I have a strange problem with unity BuildUp method. I have one interface that's mapped to three classes. I have given a name to each mapping.
Now I need to inject the dependency in an existing object (it's an attribute so I don't have control over lifetime). I call the BuildUp method to inject the dependency, but it always throws an exception which says that the interface is not mapped.
If I map the interface to one type only and I remove the mappingname, the BuildUp method works.
If I map the interface to one type only and I specify the mappingname, the BuildUp method fail.
I have tried registering types in configuration and code and nothing changes.
I suspect this is a bug, but I would like to know if anyone else has another idea.
This is how i call buildup method:
var newAttr = _container.BuildUp(myAttribute.GetType(), myAttribute, "Mapping1");
I tried to follow your scenario and this sample works
var container = new UnityContainer();
container.RegisterType<IFoo, One>("1", new InjectionProperty("Bar", "1"));
container.RegisterType<IFoo, Two>("2", new InjectionProperty("Bar", "2"));
container.RegisterType<IFoo, Three>("3", new InjectionProperty("Bar", "3"));
One one = new One();
container.BuildUp(one.GetType(), one, "1");
Assert.AreEqual("1", one.Bar);
public interface IFoo
{
string Bar { get; set; }
}
public class One : IFoo
{
public string Bar { get; set; }
}
public class Two : IFoo
{
public string Bar { get; set; }
}
public class Three : IFoo
{
public string Bar { get; set; }
}
Update
var container = new UnityContainer();
container.RegisterType<Person>(new InjectionProperty("Foo"));
container.RegisterType<IFoo, One>("1");
container.RegisterType<IFoo, Two>("2");
container.RegisterType<IFoo, Three>("3");
Person person = container.Resolve<Person>("1");
Assert.IsNotNull(person.Foo);
Assert.IsInstanceOfType(person.Foo, typeof(One));
public class Person
{
public IFoo Foo { get; set; }
}
I guess this is what you mean? Short answer: That's not the way Unity works.
Long answer: You will have to specify a ResolverOverride that does that for you. But even that is not enough as you want the container to create the value you want to inject for you. So you would need to specify a ResolvedParameter as the value for your ResolverOverride. With Unity's out-of-the-box parts the Resolve would look like this
Person person = container.Resolve<Person>(new PropertyOverride("Foo", new ResolvedParameter(typeof(IFoo), "1")));
Or you can use this custom override instead
public class NamedPropertyOverride : ResolverOverride
{
private readonly string propertyName;
private readonly string registrationName;
public NamedPropertyOverride(string propertyName, string registrationName)
{
this.propertyName = propertyName;
this.registrationName = registrationName;
}
public override IDependencyResolverPolicy GetResolver(IBuilderContext context, Type dependencyType)
{
var currentOperation = context.CurrentOperation as ResolvingPropertyValueOperation;
if (currentOperation != null &&
currentOperation.PropertyName == this.propertyName)
{
Type propertyType = currentOperation
.TypeBeingConstructed
.GetProperty(currentOperation.PropertyName, BindingFlags.Instance | BindingFlags.Public)
.PropertyType;
return new NamedTypeDependencyResolverPolicy(propertyType, this.registrationName);
}
return null;
}
}
Change the line that contains the call to Resolve in the above sample to this one
Person person = container.Resolve<Person>(new NamedPropertyOverride("Foo", "1"));
That should do the trick.
Related
I am having problems understanding how to use RegisterFactory. The code below works fine with the older InjectionFactory but I am having problems when I try to do the same thing with RegisterFactory.
In the sample code there is an uncommented section that uses RegisterFactory and a commented section that uses InjectionFactory. The InjectionFactory code works fine but the RegisterFactory throws an ResolutionFailedException.
Unity.ResolutionFailedException: 'The current type, ConsoleApp1.IFoo, is an interface and cannot be constructed. Are you missing a type mapping?
What am I doing incorrectly?
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.EnableDebugDiagnostic();
container.RegisterType<IFoo, Foo1>("Foo1");
container.RegisterType<IFoo, Foo2>("Foo2");
container.RegisterType<MainViewModel>();
// This does not work
container.RegisterFactory<Func<string, IFoo>>((c, type, name) => c.Resolve<IFoo>(name));
// This works
//container.RegisterType<Func<string, IFoo>>(new InjectionFactory(
// ctx => new Func<string, IFoo>(name => container.Resolve<IFoo>(name))));
var vm = container.Resolve<MainViewModel>();
}
}
public class MainViewModel
{
public MainViewModel(Func<string, IFoo> fooFactory)
{
var foo1 = fooFactory.Invoke("Foo1");
var foo2 = fooFactory.Invoke("Foo2");
}
}
public interface IFoo
{
string Name { get; }
}
public class Foo1 : IFoo
{
public string Name { get; set; }
public Foo1()
{
Name = "Foo1";
}
}
public class Foo2 : IFoo
{
public string Name { get; set; }
public Foo2()
{
Name = "Foo2";
}
}
If you're registering with RegisterFactory, you tell Unity how to construct the instance. But Unity already knows how to construct Foo1 and Foo2, because you registered those already.
What you want is a factory for you to use, that's what RegisterType does, so this works.
Normally, such a factory would implement some IFooFactory, thus making the context more obvious. But as long as Func<string, IFoo> is registered only used once, it works fine, too, of course.
Here is my Session Class
public static class Sessions
{
public class UserSession
{
public string CurrentSelected
{
get;
set;
}
public string Req
{
get;
set;
}
public DateTime Reque
{
get;
set;
}
public List<Options> Option;
}
public class Option
{
public string Te;
public string Fe;
public string Fg;
public string DE;
}
}
I create a new session of my class
Session["SessionStats"] = new UserSession();
Then I try to add to the List
foreach(string hello in helloworld) {
Options RO = new Options();
RO.DE = item.GetDataKeyValue("DE").ToString();
RO.Fg = item.GetDataKeyValue("Fg").ToString();
RO.Fe = item.GetDataKeyValue("Fe").ToString();
RO.Te = item.GetDataKeyValue("Te").ToString();
}
This is where the error occurs
((UserSession)Session["SessionStats"]).Options.Add(RO);
RO is correctly populated but ((UserSession)Session["SessionStats"]).Option is null, I'm not sure how to add RO to this list. This has to be a list because I have like 10 RO's I need to put in this list.
After
Session["SessionStats"] = new UserSession();
you have added a new UserSession, whose Option property is null, to Session. Then, when you do
((UserSession)Session["SessionStats"]).Options.Add(RO);
you are pulling out that very same object and accessing the Option property, which is null, hence the NullReferenceException.
It looks like you are forgetting to assign something to the newly created UserOption's Option property. However, you don't seem to be using the Options you are instantiating in the foreach for anything...
You are mixing 'Option' and 'Options'. Change the class name from 'Option' to 'Options'. Then change this line:
((UserSession)Session["SessionStats"]).Options.Add(RO);
to
((UserSession)Session["SessionStats"]).Option.Add(RO);
recently posted about questioning how unsafe static variables are, I've since discovered I need to get rid of them. But I cannot figure out how to? Was thinking a static Get() method for each class, that returns a single instance, but then that instance would have to be declared static.
So the only way to do it, is to have the instance references (for each helper, I.E user helper.cs, imagehelper.cs etc.) is to declare them as instance properties on some sort of globally accessible class? But which class? Is there something I'm missing here?
Code below of a sample class I need to change:
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Mvc.Mailer;
namespace MVCWebsite.Helpers
{
public class AppSettings
{
public static void OnAppInit()
{
//General
AppName = "MyApp";
DesktopBaseURLs = new Dictionary<string, string>();
DesktopBaseURLs.Add("dev", "localhost:50560");
DesktopBaseURLs.Add("test", "www.test.whatever.com");
DesktopBaseURLs.Add("live", "www.whatever.com");
MobileBaseURLs = new Dictionary<string, string>();
MobileBaseURLs.Add("dev", "m.local.whatever.com");
MobileBaseURLs.Add("test", "m.test.whatever.com");
MobileBaseURLs.Add("live", "m.whatever.com");
//Emails
EmailHostName = AppName + ".com"; //For the moment atleast
NoReplyEmailAddress = "no-reply#" + EmailHostName.ToLower();
SupportEmailAddress = "support#" + EmailHostName.ToLower();
ErrorEmailAddress = "errors#" + EmailHostName.ToLower();
//Resources
TempFileURL = "/content/temp/";
UserDataURL = "/content/user-content/";
ProfilePicturesURL = UserDataURL + "profile-pictures/";
var a = GlobalHelper.GetURLAsServerPath(ProfilePicturesURL);
var b = a;
}
//General
public static string AppName { get; set; }
public static Dictionary<string, string> DesktopBaseURLs;
public static Dictionary<string, string> MobileBaseURLs;
//Emails
public static string EmailHostName { get; set; }
public static string NoReplyEmailAddress { get; set; }
public static string SupportEmailAddress { get; set; }
public static string ErrorEmailAddress { get; set; }
//Resources
public static string UserDataURL { get; set; }
public static string TempFileURL { get; set; }
public static string ProfilePicturesURL { get; set; }
//Methods
public static void SetAppURL()
{
}
}
}
I recommend creating an interface for your AppSettings class, so that you can use it in your controllers now, and implement it in different ways as you see fit:
public interface IAppSettings
{
string AppName { get; set; }
...
}
You can then implement it immediately with your static class via a wrapper class:
public class AppSettingsWrapper : IAppSettings
{
public AppName
{
get
{
return AppSettings.AppName;
}
set
{
AppSettings.AppName = value;
}
}
...
}
Later on, you can create an implementation of IAppSettings that uses session, or cookies, or database values, or whatever. The important thing is to abstract the way you store things so that you can implement in a way that meets your needs.
The answer to you previous question clearly stated that the IDictionary was the only unsafe variable in your static method because it's not thread safe. You just need to store these variables differently. You don't need to get rid of all of your static variables. You just need to change IDictionary to something thread safe.
By the way, someone there makes a good coment about web.config
Right I think I've figured it out, they should be stored as instance variables within Global.asax.cs. This file contains your Application class which inherits from System.Web.HttpApplication. This master class is limited to one instance (of itself) per request. So if you store any references to your helpers here, you can reference them by going, MvcApplication.MyHelper.DoSomething(); Someone please correct me if this is wrong, but seems right to me. "At any single point of time, an HTTPApplication instance handles only one request, so we don't need to think about locking and unlocking of any non static members, but for static members we do require. " -from : http://www.codeproject.com/Articles/87316/A-walkthrough-to-Application-State#c
Is it possible to specify an object as a parameter in MVC with default values in some way?
E.g.
public virtual ViewResult Index(RequirementFilters requirementFilters)
I'd like to initialize the values of a couple of parameters on RequirementFilters?
At the moment I am doing
public virtual ViewResult Index(int status=1, bool required =false)
I wanted to create a Filter Object so I could re-use it but I can't figure out way of setting defaults for the object in the Action Parameters.
Thanks
Graeme
You could create a custom ActionFilter attribute and create an instance of your Filter Object there. You can provide some properties through the custom attribute.
Here's an example:
public class DefaultQuerySettingsAttribute : ActionFilterAttribute
{
public string ParameterName { get; set; }
public Type SettingsType { get; set; }
public int Rows { get; set; }
public string SortColumn { get; set; }
public string SortOrder { get; set; }
public bool PagingEnabled { get; set; }
public DefaultQuerySettingsAttribute()
{
this.ParameterName = "settings";
var defaultSettings = new QuerySettings();
this.Rows = defaultSettings.Rows;
this.SortColumn = defaultSettings.SortColumn;
this.SortOrder = defaultSettings.SortOrder;
this.PagingEnabled = defaultSettings.PagingEnabled;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (filterContext.ActionParameters.ContainsKey(this.ParameterName))
{
var querySettings = filterContext.ActionParameters[this.ParameterName] as QuerySettings;
if (querySettings == null || string.IsNullOrWhiteSpace(querySettings.SortColumn))
filterContext.ActionParameters[this.ParameterName] = this.GetQuerySettings();
}
}
private QuerySettings GetQuerySettings()
{
var querySettings = (QuerySettings)Activator.CreateInstance(SettingsType ?? typeof(QuerySettings));
querySettings.Rows = Rows;
querySettings.SortColumn = SortColumn;
querySettings.SortOrder = SortOrder;
querySettings.PagingEnabled = PagingEnabled;
return querySettings;
}
}
ParameterName is the name of the argument in the action method (requirementFilters in your case).
You can also specify actual type that will be instantiated by providing SettingsType.
Users sometimes prefer to see the defaults on screen, rather than allowing the system to hide the defaults internally.
A better way of having defaults will be to actually show the defaults on int UI, in the HTML by rendering it with together with the defaults. That way when someone posts the page, the defaults which you pre-rendered is also posted and binded to the model.
So try and see if you can render with defaults whatever for you are rendering and posted to the Index action.
Finally, if you can't do it that way, what is preventing you from initializing the properties with default values in the no-arg constructor while creating the object?
EDIT
Or you can use the C# language feature the null coalescent operator to implement defaults. Look here to read about it.
As long as you don't need to change the defaults per action, you can set them in the default constructor of the Model.
I am trying to test a property that is nested in a child class.
I always get an error.
Am I missing something?
Is it possible to test a child property in moq.
I have the following
[Test]
public void Should_be_able_to_test_orderCollection()
{
var orderViewMock = new Mock<IOrderView>();
orderViewMock.SetupGet(o => o.Customer.OrderDataCollection.Count).Returns(2);
orderViewMock.SetupSet(o => o.Customer.OrderDataCollection[1].OrderId = 1);
orderViewMock.VerifySet(o => o.Customer.OrderDataCollection[1].OrderId=1);
}
public class CustomerTestHelper
{
public static CustomerInfo GetCustomer()
{
return new CustomerInfo
{
OrderDataCollection = new OrderCollection
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
};
}
}
public class CustomerInfo
{
public OrderCollection OrderDataCollection { get; set; }
}
public class OrderCollection:List<Order>
{
}
public class Order
{
public int OrderId { get; set; }
}
public interface IOrderView
{
CustomerInfo Customer { get; set; }
}
You can't mock the OrderDataCollection property of CustomerInfo because it's a non-virtual property on a concrete class.
The best way to fix this would be to extract an interface from CustomerInfo and let IOrderView return that instead:
public interface IOrderView
{
ICustomerInfo Customer { get; set; }
}
It is definitely possible if you have the right abstractions. You need to mock your Customer and its children too, for your example to work, like:
var customerMock = new Mock<ICustomer>();
orderViewMock.SetupGet(o => o.Customer).Returns(customerMock.Object);
etc. for the entire hierarchy of child objects you want to control with mocks. Hope it makes sense.
/Klaus
You will get a runtime error, as you've found:
System.ArgumentException: Invalid setup on a non-overridable member:
o => o.Customer.OrderDataCollection.Count
at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo)
You can mock the IOrderView and return any CustomerInfo instance you want, but you're also trying to mock CustomerInfo and OrderCollection. As Mark Seemann mentioned, you can only mock interfaces and virtual properties/methods. This will hold true for almost any mocking/isolation framework except for Typemock (commercial).
As others have already stated, one way to solve the problem is to return an interface for the customer.