Unity.BuildUp unable to disambiguate - unity-container

I have a class with two constructors, both constructors have one parameter. Due to restrictions not worth explaining I cannot alter the constructors or use a descendent class.
I can't use unity to create instances of this class because Unity sees 2 constructors with the same number of parameters and complains that it doesn't know which to use, which is fair enough. So instead I create the instance myself and then try to use UnityContainer.BuildUp()
var result = constructorInfo.Invoke(new object[] { content });
UnitContainer.BuildUp(result);
The above code does not set any of my [Dependency] properties nor does it call an [InjectionMethod] if I use that instead.
var result = constructorInfo.Invoke(new object[] { content });
UnitContainer.BuildUp(typeOfObject, result);
This throws another exception about ambiguous constructors, even though I am not asking it to construct the instance.
Does anyone have any ideas?
Here is an example app
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using System.Reflection;
namespace ConsoleApplication7
{
public interface IConstructorType1 { }
public interface IConstructorType2 { }
public interface INeedThisDependency { }
public class NeedThisDependency : INeedThisDependency { }
public class MyDomainObject
{
public MyDomainObject(IConstructorType1 constructorType1) { }
public MyDomainObject(IConstructorType2 constructorType2) { }
[Dependency]
public INeedThisDependency Needed { get; set; }
}
class Program
{
static void Main(string[] args)
{
IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<INeedThisDependency, NeedThisDependency>();
//Try with type 1 constructor
ConstructorInfo constructorInfo1 = typeof(MyDomainObject).GetConstructor(new Type[] { typeof(IConstructorType1) });
MyDomainObject instance1 = CreateTheInstance(unityContainer, typeof(MyDomainObject), constructorInfo1, null);
//Try with type 2 constructor
ConstructorInfo constructorInfo2 = typeof(MyDomainObject).GetConstructor(new Type[] { typeof(IConstructorType2) });
MyDomainObject instance2 = CreateTheInstance(unityContainer, typeof(MyDomainObject), constructorInfo2, null);
}
//This is the only point I have any influence over what happens
//So this is the only place I get to change the code.
static MyDomainObject CreateTheInstance(IUnityContainer unityContainer, Type type, ConstructorInfo constructorInfo, object parameters)
{
var result = (MyDomainObject)constructorInfo.Invoke(new object[] { parameters });
//This will throw an ambiguous constructor exception,
//even though I am not asking it to construct anything
unityContainer.BuildUp(type, result);
//This will not build up dependencies
unityContainer.BuildUp(result);
if (result.Needed == null)
throw new NullReferenceException("Needed");
return result;
}
}
}

It's a bug in BuildUp, unfortunately.

Instead of calling BuildUp call this CallInjectionMethod helper.
public static class UnityContainerHelper
{
public static void CallInjectionMethod(this IUnityContainer unityContainer, object instance, params ResolverOverride[] overrides)
{
if (instance == null)
throw new ArgumentNullException("Instance");
var injectionMethodInfo = instance.GetType().GetMethods().Where(x => x.GetCustomAttributes(typeof(InjectionMethodAttribute), true).Any()).SingleOrDefault();
if (injectionMethodInfo == null)
return;
var parameters = injectionMethodInfo.GetParameters();
if (parameters.Length == 0)
return;
var dependencies = new object[parameters.Length];
int index = 0;
foreach (Type parameterType in parameters.Select(x => x.ParameterType))
{
dependencies[index] = unityContainer.Resolve(parameterType, overrides);
index++;
}
injectionMethodInfo.Invoke(instance, dependencies);
}
}

Related

How to test a class with delegate in constructor using Moq

Can someone explain to me how to create an instance of this component in a Moq TestMethod? Here is the definition of the class. I need to test the ProcessAutomaticFillRequest method.
public class AutomaticDispenserComponent : IAutomaticDispenserComponent
{
private readonly Lazy<IMessageQueueComponent> _messageQueueComponent;
protected IMessageQueueComponent MessageQueueComponent { get { return _messageQueueComponent.Value; } }
public AutomaticDispenserComponent(Func<IMessageQueueComponent> messageQueueComponentFactory)
{
_messageQueueComponent = new Lazy<IMessageQueueComponent>(messageQueueComponentFactory);
}
public void ProcessAutomaticFillRequest(FillRequestParamDataContract fillRequestParam)
{
if (fillRequestParam.PrescriptionServiceUniqueId == Guid.Empty)
throw new InvalidOperationException("No prescription service was specified for processing fill request.");
if (fillRequestParam.Dispenser == null)
throw new InvalidOperationException("No dispenser was specified for processing fill request.");
var userContext = GlobalContext.CurrentUserContext;
var channel = string.Format(Channel.FillRequest, userContext.TenantId,
userContext.PharmacyUid, fillRequestParam.Dispenser.DeviceAgentUniqueId);
NotificationServer.Publish(channel, fillRequestParam);
}
Here is how I started my test, but I don't know how to create an instance of the component:
[TestMethod]
[ExpectedException(typeof (InvalidOperationException))]
public void FillRequestFailsWhenPrescriptionServiceUniqueIdIsEmpty()
{
// How do I create an instance of automatiqueDispenserComponent here
// since there is Func as constructor parameter?
var fillRequestParam = new FillRequestParamDataContract
{
PrescriptionServiceUniqueId = Guid.Empty
};
_automaticDispensercomponent.ProcessAutomaticFillRequest(fillRequestParam);
// ...
}
Updated the answer based on the comments below. You need to mock the Func parameter for the test.
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void FillRequestFailsWhenPrescriptionServiceUniqueIdIsEmpty()
{
var mockMsgQueueComponent = new Mock<Func<IMessageQueueComponent>>();
var _automaticDispensercomponent = new AutomaticDispenserComponent
(mockMsgQueueComponent.Object);
var fillRequestParam = new FillRequestParamDataContract
{
PrescriptionServiceUniqueId = Guid.Empty
};
_automaticDispensercomponent.ProcessAutomaticFillRequest(fillRequestParam);
}

Using one session per request, how to handle updating child objects

I'm having some serious issues with Fluent Nhibernate in my ASP.NET WebForms app when trying to modify a child object and then saving the parent object.
My solution is currently made of 2 projects :
Core : A class library where all entities & repositories classes are located
Website : The ASP.NET 4.5 WebForms application
Here is my simple mapping for my Employee object:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.DateCreated);
Map(x => x.Username);
Map(x => x.FirstName);
Map(x => x.LastName);
HasMany(x => x.TimeEntries).Inverse().Cascade.All().KeyColumn("Employee_id");
}
}
Here is my my mapping for the TimeEntry object:
public class TimeEntryMap : ClassMap<TimeEntry>
{
public TimeEntryMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.DateCreated);
Map(x => x.Date);
Map(x => x.Length);
References(x => x.Employee).Column("Employee_id").Not.Nullable();
}
}
As stated in the title, i'm using one session per request in my web app, using this code in Gobal.asax:
public static ISessionFactory SessionFactory = Core.SessionFactoryManager.CreateSessionFactory();
public static ISession CurrentSession
{
get { return (ISession)HttpContext.Current.Items["current.session"]; }
set { HttpContext.Current.Items["current.session"] = value; }
}
protected Global()
{
BeginRequest += delegate
{
System.Diagnostics.Debug.WriteLine("New Session");
CurrentSession = SessionFactory.OpenSession();
};
EndRequest += delegate
{
if (CurrentSession != null)
CurrentSession.Dispose();
};
}
Also, here is my SessionFactoryManager class:
public class SessionFactoryManager
{
public static ISession CurrentSession;
public static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("Website.Properties.Settings.WebSiteConnString")))
.Mappings(m => m
.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true))
.BuildSessionFactory();
}
public static ISession GetSession()
{
return (ISession)HttpContext.Current.Items["current.session"];
}
}
Here is one of my repository class, the one i use to handle the Employee's object data operations:
public class EmployeeRepository<T> : IRepository<T> where T : Employee
{
private readonly ISession _session;
public EmployeeRepository(ISession session)
{
_session = session;
}
public T GetById(int id)
{
T result = null;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Get<T>(id);
tx.Commit();
}
return result;
}
public IList<T> GetAll()
{
IList<T> result = null;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Query<T>().ToList();
tx.Commit();
}
return result;
}
public bool Save(T item)
{
var result = false;
using (ITransaction tx = _session.BeginTransaction())
{
_session.SaveOrUpdate(item);
tx.Commit();
result = true;
}
return result;
}
public bool Delete(T item)
{
var result = false;
using (ITransaction tx = _session.BeginTransaction())
{
_session.Delete(_session.Load(typeof (T), item.Id));
tx.Commit();
result = true;
}
return result;
}
public int Count()
{
var result = 0;
using (ITransaction tx = _session.BeginTransaction())
{
result = _session.Query<T>().Count();
tx.Commit();
}
return result;
}
}
Now, here is my problem. When i'm trying to insert Employee(s), everything is fine. Updating is also perfect... well, as long as i'm not updating one of the TimeEntry object referenced in the "TimeEntries" property of Employee...
Here is where an exception is raised (in a ASPX file of the web project):
var emp = new Employee(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
emp.Save();
Here is the exception that is raised:
[NonUniqueObjectException: a different object with the same identifier
value was already associated with the session: 1, of entity:
Core.Entities.Employee]
Basically, whenever I try to
Load an employee and
Modify one of the saved TimeEntry, I get that exception.
FYI, I tried replacing the SaveOrUpdate() in the repository for Merge(). It did an excellent job, but when creating an object using Merge(), my object never gets it's Id set.
I also tried creating and flushing the ISession in each function of my repository. It made no sense because as soon as i was trying to load the TimeEntries property of an Employee, an exception was raised, saying the object could not be lazy-loaded as the ISession was closed...
I'm at lost and would appreciate some help. Any suggestion for my repository is also welcome, as i'm quite new to this.
Thanks you guys!
This code
var emp = new Employee(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
emp.Save();
is creating a new Employee object, presumable with an ID of 1 passed through the constructor. You should be loading the Employee from the database, and your Employee object should not allow the ID to be set since you are using an identity column. Also, a new Employee would not have any TimeEntries and the error message clearly points to an Employee instance as the problem.
I'm not a fan of transactions inside repositories and I'm really not a fan of generic repositories. Why is your EmployeeRepository a generic? Shouldn't it be
public class EmployeeRepository : IRepository<Employee>
I think your code should look something like:
var repository = new EmployeeRepository(session);
var emp = repository.GetById(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
repository.Save(emp);
Personally I prefer to work directly with the ISession:
using (var txn = _session.BeginTransaction())
{
var emp = _session.Get<Employee>(1);
foreach (var timeEntry in emp.TimeEntries)
{
timeEntry.Length += 1;
}
txn.Commit();
}
This StackOverflow Answer gives an excellent description of using merge.
But...
I believe that you are facing issues with setting up a correct session pattern for your application.
I you suggest to take a look at session-per-request pattern
where in you create a single NHibernate session object per request. the session is opened when the request is received and closed/flushed on generating a response.
Also make sure that instead of using SessionFactory.OpenSession() to get a session try using SessionFactory.GetCurrentSession() which puts the onus on NHibernate to return you the current correct session.
I hope this pushes you in the right direction.

AutoFixture: mock methods don't return a frozen instance

I'm trying to write this simple test:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var postProcessingAction = fixture.Freeze<Mock<IPostProcessingAction>>();
var postProcessor = fixture.Freeze<PostProcessor>();
postProcessor.Process("", "");
postProcessingAction.Verify(action => action.Do());
The Verify check fails.
The code for postProcessor.Process is
public void Process(string resultFilePath, string jobId)
{
IPostProcessingAction postProcessingAction =
postProcessingActionReader
.CreatePostProcessingActionFromJobResultXml(resultFilePath);
postProcessingAction.Do();
}
postProcessingActionReader is an interface field initialized through the constructor.
I'm expecting the test to pass but it fails, it turns out the instance of IPostProessingAction returned from the CreatePostProcessingActionFromJobResultXml method is not the same instance as returned from fixture.Freeze<>.
My expectation was that after freezing this Mock object it would inject the underlying mock of the IPostProcessingAction interface in every place its required as well as make all mock methods returning IPostProcessingAction return this same object.
Is my expectation about the return value of the mock methods incorrect?
Is there a way to change this behavior so that mock methods return the same frozen instance?
You need to Freeze the IPostProcessingActionReader component.
The following test will pass:
[Fact]
public void Test()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization());
var postProcessingActionMock = new Mock<IPostProcessingAction>();
var postProcessingActionReaderMock = fixture
.Freeze<Mock<IPostProcessingActionReader>>();
postProcessingActionReaderMock
.Setup(x => x.CreatePostProcessingActionFromJobResultXml(
It.IsAny<string>()))
.Returns(postProcessingActionMock.Object);
var postProcessor = fixture.CreateAnonymous<PostProcessor>();
postProcessor.Process("", "");
postProcessingActionMock.Verify(action => action.Do());
}
Assuming that the types are defined as:
public interface IPostProcessingAction
{
void Do();
}
public class PostProcessor
{
private readonly IPostProcessingActionReader actionReader;
public PostProcessor(IPostProcessingActionReader actionReader)
{
if (actionReader == null)
throw new ArgumentNullException("actionReader");
this.actionReader = actionReader;
}
public void Process(string resultFilePath, string jobId)
{
IPostProcessingAction postProcessingAction = this.actionReader
.CreatePostProcessingActionFromJobResultXml(resultFilePath);
postProcessingAction.Do();
}
}
public interface IPostProcessingActionReader
{
IPostProcessingAction CreatePostProcessingActionFromJobResultXml(
string resultFilePath);
}
In case you use AutoFixture declaratively with the xUnit.net extension the test could be simplified even further:
[Theory, AutoMoqData]
public void Test(
[Frozen]Mock<IPostProcessingActionReader> readerMock,
Mock<IPostProcessingAction> postProcessingActionMock,
PostProcessor postProcessor)
{
readerMock
.Setup(x => x.CreatePostProcessingActionFromJobResultXml(
It.IsAny<string>()))
.Returns(postProcessingActionMock.Object);
postProcessor.Process("", "");
postProcessingActionMock.Verify(action => action.Do());
}
The AutoMoqDataAttribute is defined as:
internal class AutoMoqDataAttribute : AutoDataAttribute
{
internal AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
As of 3.20.0, you can use AutoConfiguredMoqCustomization. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
In other words, it will auto-configure your postProcessingActionReader to return the frozen postProcessingAction.
Just change this:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
to this:
var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization());

How can i use engine object in my console application

"How can i use engine in my console application"
I shouldn't use the ITemplate-interface and Transform-Method.
I am using Tridion 2011
Could anyone please suggest me.
You can't. The Engine class is part of the TOM.NET and that API is explicitly reserved for use in:
Template Building Blocks
Event Handlers
For all other cases (such as console applications) you should use the Core Service.
There are many good questions (and articles on other web sites) already:
https://stackoverflow.com/search?q=%5Btridion%5D+core+service
http://www.google.com/#q=tridion+core+service
If you get stuck along the way, show us the relevant code+configuration you have and what error message your get (or at what step you are stuck) and we'll try to help from there.
From a console application you should use the Core Service. I wrote a small example using the Core Service to search for items in the content manager.
Console.WriteLine("FullTextQuery:");
var fullTextQuery = Console.ReadLine();
if (String.IsNullOrWhiteSpace(fullTextQuery) || fullTextQuery.Equals(":q", StringComparison.OrdinalIgnoreCase))
{
break;
}
Console.WriteLine("SearchIn IdRef:");
var searchInIdRef = Console.ReadLine();
var queryData = new SearchQueryData
{
FullTextQuery = fullTextQuery,
SearchIn = new LinkToIdentifiableObjectData
{
IdRef = searchInIdRef
}
};
var results = coreServiceClient.GetSearchResults(queryData);
results.ToList().ForEach(result => Console.WriteLine("{0} ({1})", result.Title, result.Id));
Add a reference to Tridion.ContentManager.CoreService.Client to your Visual Studio Project.
Code of the Core Service Client Provider:
public interface ICoreServiceProvider
{
CoreServiceClient GetCoreServiceClient();
}
public class CoreServiceDefaultProvider : ICoreServiceProvider
{
private CoreServiceClient _client;
public CoreServiceClient GetCoreServiceClient()
{
return _client ?? (_client = new CoreServiceClient());
}
}
And the client itself:
public class CoreServiceClient : IDisposable
{
public SessionAwareCoreServiceClient ProxyClient;
private const string DefaultEndpointName = "netTcp_2011";
public CoreServiceClient(string endPointName)
{
if(string.IsNullOrWhiteSpace(endPointName))
{
throw new ArgumentNullException("endPointName", "EndPointName is not specified.");
}
ProxyClient = new SessionAwareCoreServiceClient(endPointName);
}
public CoreServiceClient() : this(DefaultEndpointName) { }
public string GetApiVersionNumber()
{
return ProxyClient.GetApiVersion();
}
public IdentifiableObjectData[] GetSearchResults(SearchQueryData filter)
{
return ProxyClient.GetSearchResults(filter);
}
public IdentifiableObjectData Read(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
public ApplicationData ReadApplicationData(string subjectId, string applicationId)
{
return ProxyClient.ReadApplicationData(subjectId, applicationId);
}
public void Dispose()
{
if (ProxyClient.State == CommunicationState.Faulted)
{
ProxyClient.Abort();
}
else
{
ProxyClient.Close();
}
}
}
When you want to perform CRUD actions through the core service you can implement the following methods in the client:
public IdentifiableObjectData CreateItem(IdentifiableObjectData data)
{
data = ProxyClient.Create(data, new ReadOptions());
return data;
}
public IdentifiableObjectData UpdateItem(IdentifiableObjectData data)
{
data = ProxyClient.Update(data, new ReadOptions());
return data;
}
public IdentifiableObjectData ReadItem(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
To construct a data object of e.g. a Component you can implement a Component Builder class that implements a create method that does this for you:
public ComponentData Create(string folderUri, string title, string content)
{
var data = new ComponentData()
{
Id = "tcm:0-0-0",
Title = title,
Content = content,
LocationInfo = new LocationInfo()
};
data.LocationInfo.OrganizationalItem = new LinkToOrganizationalItemData
{
IdRef = folderUri
};
using (CoreServiceClient client = provider.GetCoreServiceClient())
{
data = (ComponentData)client.CreateItem(data);
}
return data;
}
Hope this gets you started.

ASP.NET NullReferenceException for get_Session()

public class MessageHelper : System.Web.UI.MasterPage
{
public MessageHelper()
{
}
public string Message
{
set { Session["Message"] = value; }
get
{
if (Session["Message"] != null)
{
var msg = Session["Message"] as string;
Session["Message"] = "";
return msg;
}
return "";
}
}
public string ErrorMsg
{
set { Session["Error"] = value; }
get
{
if (Session["Error"] != null)
{
var err = Session["Error"] as string;
Session["Error"] = "";
return err;
}
return "";
}
}
}
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.UI.UserControl.get_Session() +15
WebApplication1.MessageHelper.get_ErrorMsg() in ..file.master.cs:71
where line 71 is: if (Session["Error"] != null)
what am I doing wrong here?!
EDIT (transcribed from original author):
#David,
here is AdminMaster.master.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.SessionState;
namespace WebApplication1
{
public partial class AdminMaster : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
MessageHelper msg = new MessageHelper();
if (msg.ErrorMsg != "")
{
// do something
}
if (msg.ErrorMsg != "")
{
// do something
}
}
}
public class MessageHelper : System.Web.UI.MasterPage
{
public MessageHelper()
{
}
public string Message
{
set { System.Web.HttpContext.Current.Session["Message"] = value; }
get
{
if (System.Web.HttpContext.Current.Session["Message"] != null)
{
var msg = System.Web.HttpContext.Current.Session["Message"] as string;
System.Web.HttpContext.Current.Session["Message"] = "";
return msg;
}
return "";
}
}
public string ErrorMsg
{
set { System.Web.HttpContext.Current.Session["Error"] = value; }
get
{
if (System.Web.HttpContext.Current.Session["Error"] != null)
{
var err = System.Web.HttpContext.Current.Session["Error"] as string;
System.Web.HttpContext.Current.Session["Error"] = "";
return err;
}
return "";
}
}
}
}
so it does inherit from System.Web.UI.MasterPage, my bad.
i want the MessageHelper to be accessed from different pages on the site. all of my pages use the Master file, that's why i put the MessageHelper in the master file.
what is wrong here?
During debugging, can you confirm that Session is not null? Try referencing it fully-qualified as System.Web.HttpContext.Current.Session within this class and see if that helps any.
Edit: In response to the non-answer answer that you posted...
It's not recommended to put that helper class in the same file as your master page. Put it in its own file named for the class. (There's probably debate over whether every class should have its own file, but in this particular case it's clear that the two classes in this one file are very much unrelated and shouldn't be together.)
The class can have its own namespace, such as WebApplication1.Helpers (though I recommend in the future using something more descriptive than WebApplication1, but don't try to change it here because it'll cause errors elsewhere in the project), and other class files can reference that namespace with using WebApplication1.Helpers in order to use that class.
Separating classes into an intuitive structure in the project (or multiple projects, as things grow in complexity) will make it easier to support in the future.
And, seeing the whole file, the helper class definitely should not inherit from MasterPage. It doesn't need to, and doing so adds things to that class that shouldn't be there.
I'm a bit confused by what you're trying to achieve with the MessageHelper class.
If it is code common to your master pages then you should surely be inheriting AdminMaster from MessageHelper.
eg.
public partial class AdminMaster : MessageHelper
If not, I don't understand why MessageHelper needs to inherit from MasterPage?

Resources