MEF : Discover plugin using ExportMetaData attribute - mef

In the below code I discover all the plugins using the contract ICalculator and then pick the plugin depending on the metat data attribute.
I need to discover the plugin depending on the ExportMetadata attribute directly and not on the Interface contract type "ICalculator".
Is there any way I can do that?
Thanks!
public abstract class MathOperation : ICalculator
{
public abstract int GetNumber(int num1, int num2);
}
[Export(typeof(ICalculator))]
[ExportMetadata("CalciMetaData", "Add")]
public class Add : MathOperation
{
#region Interface members
public override int GetNumber(int num1, int num2)
{
return num1 + num2;
}
#endregion
}
[Export(typeof(ICalculator))]
[ExportMetadata("CalciMetaData", "Divide")]
public class Divide : MathOperation
{
#region Interface members
public override int GetNumber(int num1, int num2)
{
return num1 / num2;
}
#endregion
}
// Composition.
public class CalciCompositionHelper
{
[ImportMany]
public System.Lazy<ICalculator, IDictionary<string, object>>[] CalciPlugins { get; set; }
/// <summary>
/// Assembles the calculator components
/// </summary>
public void AssembleCalculatorComponents()
{
try
{
//Step 1: Initializes a new instance of the
// System.ComponentModel.Composition.Hosting.AssemblyCatalog class with the
// current executing assembly.
var catalog = new AssemblyCatalog(Assembly.LoadFrom(#"D:\Study\MEF_Program_Files\Files\SimpleCalculator-Part2\CalculatorUI\CalculatorFactory\bin\Debug\CalculatorFactory.dll"));
//Step 2: The assemblies obtained in step 1 are added to the CompositionContainer
var container = new CompositionContainer(catalog);
//Step 3: Composable parts are created here i.e. the Import and Export components
// assembles here
container.ComposeParts(this);
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Sends the result back to the client
/// </summary>
/// <param name="num1"></param>
/// <param name="num2"></param>
/// <returns></returns>
public int GetResult(int num1, int num2, string operationType)
{
int result = 0;
foreach (var CalciPlugin in CalciPlugins)
{
if ((string)CalciPlugin.Metadata["CalciMetaData"] == operationType)
{
result = CalciPlugin.Value.GetNumber(num1, num2);
break;
}
}
return result;
}
}

You should be able to use CompositionContainer.GetExports(ImportDefinition definition). In the ImportDefinition, you can set the Constraint property to match the particular metadata you are looking for. Typically you will need to know the interface type, otherwise how will you interact with the value you get from the CompositionContainer?

Related

Automapper Projectto unable to create map expression with struct

Isn't there a way to support "wrapped" domain models as structs in mapping when querying using ProjectTo?
For example, I have a struct called Edition, that represents a license edition. In the database, such column is stored as a Integer. However, when consuming a WebApi, such field is returned as a struct Edition. You might ask, if it's a WebApi, just return as int in your model. Well, that's what we are doing under the covers, but we also have a SDK for the api, and in this SDK we modeled the returned class to have the Edition instead of int, so it is clear to the developer what the data means.
We've created .net TypeConverters and Newtonjson converters and all looks good, except AutoMapper throws an exception when using ProjectTo<MyModel>
Unable to create a map expression from ScriptVersion.License (System.Nullable`1[System.Int32]) to ScriptVersionModel.License (System.Nullable`1[Licensing.Edition])
Mapping types:
ScriptVersion -> ScriptVersionModel
Contracts.ScriptVersion -> Api.V10.ScriptVersionModel
Type Map configuration:
ScriptVersion -> ScriptVersionModel
Contracts.ScriptVersion -> Api.V10.ScriptVersionModel
Property:
License
Edition + EditionTypeConverter
[TypeConverter(typeof(EditionTypeConverter))]
[Serializable]
public struct Edition : ISerializable
{
/// <summary>
/// Prefer using <see cref="Edition.Community"/> instead.
/// This only exists to support using <see cref="Edition"/> on <see cref="System.Attribute"/>.
/// </summary>
public const int CommunityNumber = 1024;
/// <summary>
/// Prefer using <see cref="Edition.Standard"/> instead.
/// This only exists to support using <see cref="Edition"/> on <see cref="System.Attribute"/>.
/// </summary>
public const int StandardNumber = 1025;
/// <summary>
/// Prefer using <see cref="Edition.Enterprise"/> instead.
/// This only exists to support using <see cref="Edition"/> on <see cref="System.Attribute"/>.
/// </summary>
public const int EnterpriseNumber = 1026;
public static readonly Edition NotLicensed = new Edition(0);
public static readonly Edition Community = new Edition(CommunityNumber);
public static readonly Edition Standard = new Edition(StandardNumber);
public static readonly Edition Enterprise = new Edition(EnterpriseNumber);
private readonly int edition;
public Edition(int edition)
{
this.edition = edition;
}
public Edition(SerializationInfo info, StreamingContext context)
{
edition = (int)info.GetValue(nameof(edition), typeof(int));
}
public override string ToString()
{
if (edition == NotLicensed)
return "Not Licensed";
if (edition == Community)
return nameof(Community);
if (edition == Standard)
return nameof(Standard);
if (edition == Enterprise)
return nameof(Enterprise);
return $"Unknown({edition})";
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is Edition))
return false;
var token = (Edition)obj;
return token.edition == edition;
}
public override int GetHashCode() => edition.GetHashCode();
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(nameof(edition), edition);
}
public static bool operator !=(Edition left, Edition right) => !(left == right);
public static implicit operator int(Edition edition) => edition.edition;
public static bool operator ==(Edition left, Edition right)
{
if (ReferenceEquals(left, null))
return ReferenceEquals(right, null);
return left.Equals(right);
}
public static Edition? From(int? edition) => edition.HasValue ? new Edition(edition.Value) : (Edition?)null;
public class EditionTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType.GetActualType() == typeof(int) ||
sourceType.GetActualType() == typeof(long) ||
base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value == null)
return null;
if (int.TryParse(value.ToString(), out int edition))
return new Edition(edition);
if (long.TryParse(value.ToString(), out long longEdition))
return new Edition((int)longEdition);
return base.ConvertFrom(context, culture, value);
}
}
}
ScriptVersionModel - returned from WebApi
public class ScriptVersionModel
{
public Edition? License{get;set;}
}
ScriptVersion - Entity framework class mapped to database
public class ScriptVersion
{
public int? License{get;set;}
}
code that triggers the error
context.ScriptVersions.Where(predicate).ProjectTo<ScriptVersionModel>();
You can use this
public IMapper InitializeMapper()
{
var configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<ScriptVersion, ScriptVersionModel>().ForMember(a => a.License, map => map.MapFrom(src => new Edition(src.License ?? 0)));
});
return configuration.CreateMapper();
}
then
var mapper = InitializeMapper();
ScriptVersionModel edition = mapper.Map<ScriptVersionModel>(new ScriptVersion { License = 12 });
or
context.ScriptVersions.Where(predicate).ProjectTo<ScriptVersionModel>();

Autofac: cannot resolve dependency using factory after ContainerBuilder.Update()

My problem is that I want to use Func<> factory to resolve dependency. And in if I use ContainerBuilder Update() (I need it for mocking some services in integration tests), this factories still resolve outdated instances.
I created simple scenario to reproduce the problem:
class Program
{
static void Main(string[] args)
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<Test>().As<ITest>();
containerBuilder.RegisterType<Test1Factory>().As<ITestFactory>();
containerBuilder.RegisterType<TestConsumer>().AsSelf();
var container = containerBuilder.Build();
var tc1 = container.Resolve<TestConsumer>();
var cbupdater = new ContainerBuilder();
cbupdater.RegisterType<Test2>().As<ITest>();
cbupdater.RegisterType<Test2Factory>().As<ITestFactory>();
cbupdater.Update(container);
var tc2 = container.Resolve<TestConsumer>();
Console.ReadLine();
}
}
public interface ITest
{
int Id { get; set; }
}
public class Test : ITest
{
public Test()
{
Id = 1;
}
public int Id { get; set; }
}
public class Test2 : ITest
{
public Test2()
{
Id = 2;
}
public int Id { get; set; }
}
public interface ITestFactory
{
ITest Create();
}
public class Test1Factory : ITestFactory
{
public ITest Create()
{
return new Test();
}
}
public class Test2Factory : ITestFactory
{
public ITest Create()
{
return new Test2();
}
}
public class TestConsumer
{
public TestConsumer(Func<ITest> testFactory, ITest test, ITestFactory customFactory)
{
Console.WriteLine("factory: " + testFactory().Id);
Console.WriteLine("direct: " + test.Id);
Console.WriteLine("MyCustomFactory: " + customFactory.Create().Id);
Console.WriteLine("*************");
Console.WriteLine();
}
}
The output is:
factory: 1 direct: 1 MyCustomFactory: 1
factory: 1 direct: 2 MyCustomFactory: 2
Notice "factory: 1" in both cases.
Am I missing something or I have to create my cusom factory in this scenario?
P.S.
Autofac 3.5.2 or 4.0 beta 8-157
.net 4.5.1
That's by design unfortunately, the reasons, I don't know. Looking at the Autofac code gives you a better insight on how they register items with the same interface definition, in short, all registrations are maintained but the last registration wins (ref). Wait...that's not all, weirdly, for Fun<...>, you actually get them in order. You can easily test by changing the constructor of the TestConsumer class to:
public TestConsumer(Func<ITest> testFactory, IEnumerable<Func<ITest>> testFactories, IEnumerable<ITest> tests, ITest test, ITestFactory customFactory)
{
// ...
}
Note that you get all the Funcs and the ITest registration. You are simply lucky that resolving ITest directly resolves to Test2.
Now, having said all of the above, there is a way described here. You have to create a container without the registration you want to override, therefore:
/// <summary>
/// This has not been tested with all your requirements
/// </summary>
private static IContainer RemoveOldComponents(IContainer container)
{
var builder = new ContainerBuilder();
var components = container.ComponentRegistry.Registrations
.Where(cr => cr.Activator.LimitType != typeof(LifetimeScope))
.Where(cr => cr.Activator.LimitType != typeof(Func<ITest>));
foreach (var c in components)
{
builder.RegisterComponent(c);
}
foreach (var source in container.ComponentRegistry.Sources)
{
builder.RegisterSource(source);
}
return builder.Build();
}
And you can simply change your main method to the following:
static void Main(string[] args)
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<Test>().As<ITest>();
containerBuilder.RegisterType<Test1Factory>().As<ITestFactory>();
containerBuilder.RegisterType<TestConsumer>().AsSelf();
var container = containerBuilder.Build();
var tc1 = container.Resolve<TestConsumer>();
container = RemoveOldComponents(container);
var cbupdater = new ContainerBuilder();
cbupdater.RegisterType<Test2>().As<ITest>();
cbupdater.RegisterType<Test2Factory>().As<ITestFactory>();
cbupdater.Update(container);
var tc2 = container.Resolve<TestConsumer>();
Console.ReadLine();
}
PS: Wouldn't it be great to have a method which does the exact opposite of PreserveExistingDefaults()

How to UnitTest a Service with EntityFramework, Repository and Moq?

Im working on a C# Project that uses Entity Framework, Repository-Pattern, UnitOfWork-Pattern and Moq.
I´m new to EF and Unit Tests with Moq and got the following problem:
I get null pointers, when i try to test the methods from the service class...and it seems as if the context can´t get instantiated. Can anyone point my mistake out or provide me with a link?
Example:
portionService.cs
/// <summary>
/// The PortionService class represents a service for the Portion model.
/// </summary>
public class PortionService : Service, IPortionService
{
/// <summary>
/// In this constructor the base constructor of the Service class is called.
/// </summary>
/// <param name="context">Represents a context of the data access layer.</param>
public PortionService(IDALContext context) : base(context) { }
public void Add(Portion portion)
{
context.Portion.Create(portion);
context.SaveChanges();
}
public Portion GetPortionByName(string name)
{
return context.Portion.GetAll().Where(p => p.Name.ToUpper() == name.ToUpper()).LastOrDefault();
}
portionServiceTests.cs
// TestClass for PortionService-Tests
[TestClass]
public class PortionServiceTests
{
private PortionService _portionService;
// define the mock object
private Mock<IPortionService> _portionServiceMock;
[TestInitialize]
public void Init()
{
_portionService = new PortionService(new DALContext());
// create the mock object
_portionServiceMock = new Mock<IPortionService>();
}[TestMethod]
public void EnteringPortionNameReturnsThePortion()
{
//arrange
// arrange data
Portion portion = new Portion { PortionID = 12, Name = "testPortion" };
//arrange expectations
_portionServiceMock.Setup(service => service.GetPortionByName("testPortion")).Returns(portion).Verifiable();
//act
var result = _portionService.GetPortionByName("testPortion");
//verify
Assert.AreEqual(portion, result.Name);
}
DALContext.cs
public class DALContext : IDALContext, IDisposable
{
/// <summary>
/// The _context property represents the context to the current Database.
/// </summary>
private DatabaseContext _context;
private Repository<Portion> _portionRepository;
...
/// <summary>
/// In this constructor the single instance of the DataBaseContext gets instantiated.
/// </summary>
public DALContext()
{
_context = new DatabaseContext();
}
You are trying to verify the mock result to an actual data in the database, that's why it fails. Your unit test should test the service, and that the service calls the context, not the mock of the service itself.
The following example uses FakeDbSet approach from Rowan Miller's article.
using System.Data.Entity;
using System.Linq;
using Moq;
using NUnit.Framework;
using SharpTestsEx;
namespace StackOverflowExample.EntityFramework
{
public class DataEntity
{
public int Id { get; set; }
public string Data { get; set; }
}
public interface IContext
{
IDbSet<DataEntity> DataEntities { get; }
}
public class DataService
{
private IContext _db;
public DataService(IContext context)
{
_db = context;
}
public DataEntity GetDataById(int id)
{
return _db.DataEntities.First(d => d.Id == id);
}
}
[TestFixture]
public class DataServiceTests
{
[Test]
public void GetDataByIdTest()
{
//arrange
var datas = new FakeDbSet<DataEntity>
{
new DataEntity {Id = 1, Data = "one"},
new DataEntity {Id = 2, Data = "two"}
};
var context = new Mock<IContext>();
context.SetupGet(c => c.DataEntities).Returns(datas);
var service = new DataService(context.Object);
//act
var result = service.GetDataById(2);
//assert
result.Satisfy(r =>
r.Id == 2
&& r.Data == "two");
}
}
}
it's actually not easy to unit test EF based application. I would recommend using a library like effort to mock the entity framework.

Unit test Entity Framework using moq

I'm using entity framework and trying to unit test my data services which are using EF.
I'm not using repository and unit of work patterns.
I tried the following approach to mock the context and DbSet:
private static Mock<IEFModel> context;
private static Mock<IDbSet<CountryCode>> idbSet;
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
context = new Mock<IEFModel>();
idbSet = new Mock<IDbSet<CountryCode>>();
context.Setup(c => c.CountryCodes).Returns(idbSet.Object);
}
I get null "Object reference not set to an instance of an object" error for idbSet "Local".
Is there any way to mock idbSet like this?
Thanks
I worked it out like this:
Created two classes named DbSetMock:
public class DbSetMock<T> : IDbSet<T>
where T : class
{
#region Fields
/// <summary>The _container.</summary>
private readonly IList<T> _container = new List<T>();
#endregion
#region Public Properties
/// <summary>Gets the element type.</summary>
public Type ElementType
{
get
{
return typeof(T);
}
}
/// <summary>Gets the expression.</summary>
public Expression Expression
{
get
{
return this._container.AsQueryable().Expression;
}
}
/// <summary>Gets the local.</summary>
public ObservableCollection<T> Local
{
get
{
return new ObservableCollection<T>(this._container);
}
}
/// <summary>Gets the provider.</summary>
public IQueryProvider Provider
{
get
{
return this._container.AsQueryable().Provider;
}
}
#endregion
#region Public Methods and Operators
/// <summary>The add.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Add(T entity)
{
this._container.Add(entity);
return entity;
}
/// <summary>The attach.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Attach(T entity)
{
this._container.Add(entity);
return entity;
}
/// <summary>The create.</summary>
/// <typeparam name="TDerivedEntity"></typeparam>
/// <returns>The <see cref="TDerivedEntity"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
throw new NotImplementedException();
}
/// <summary>The create.</summary>
/// <returns>The <see cref="T"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public T Create()
{
throw new NotImplementedException();
}
/// <summary>The find.</summary>
/// <param name="keyValues">The key values.</param>
/// <returns>The <see cref="T"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
/// <summary>The get enumerator.</summary>
/// <returns>The <see cref="IEnumerator"/>.</returns>
public IEnumerator<T> GetEnumerator()
{
return this._container.GetEnumerator();
}
/// <summary>The remove.</summary>
/// <param name="entity">The entity.</param>
/// <returns>The <see cref="T"/>.</returns>
public T Remove(T entity)
{
this._container.Remove(entity);
return entity;
}
#endregion
#region Explicit Interface Methods
/// <summary>The get enumerator.</summary>
/// <returns>The <see cref="IEnumerator"/>.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this._container.GetEnumerator();
}
#endregion
}
and EFModelMock:
public class EFModelMock : IEFModel
{
#region Fields
/// <summary>The country codes.</summary>
private IDbSet<CountryCode> countryCodes;
#endregion
#region Public Properties
/// <summary>Gets the country codes.</summary>
public IDbSet<CountryCode> CountryCodes
{
get
{
this.CreateCountryCodes();
return this.countryCodes;
}
}
#endregion
#region Public Methods and Operators
/// <summary>The commit.</summary>
/// <exception cref="NotImplementedException"></exception>
public void Commit()
{
throw new NotImplementedException();
}
/// <summary>The set.</summary>
/// <typeparam name="T"></typeparam>
/// <returns>The <see cref="IDbSet"/>.</returns>
/// <exception cref="NotImplementedException"></exception>
public IDbSet<T> Set<T>() where T : class
{
throw new NotImplementedException();
}
#endregion
#region Methods
/// <summary>The create country codes.</summary>
private void CreateCountryCodes()
{
if (this.countryCodes == null)
{
this.countryCodes = new DbSetMock<CountryCode>();
this.countryCodes.Add(
new CountryCode { CountryName = "Australia", DisplayLevel = 2, TelephoneCode = "61" });
}
}
#endregion
}
Then tested like this:
[TestClass]
public class CountryCodeServiceTest
{
#region Static Fields
/// <summary>The context.</summary>
private static IEFModel context;
#endregion
#region Public Methods and Operators
/// <summary>The initialize.</summary>
/// <param name="testContext">The test context.</param>
[ClassInitialize]
public static void Initialize(TestContext testContext)
{
context = new EFModelMock();
}
/// <summary>The country code service get country codes returns correct data.</summary>
[TestMethod]
public void CountryCodeServiceGetCountryCodesReturnsCorrectData()
{
// Arrange
var target = new CountryCodeService(context);
var countryName = "Australia";
var expected = context.CountryCodes.ToList();
// Act
var actual = target.GetCountryCodes();
// Assert
Assert.IsNotNull(actual);
Assert.AreEqual(actual.FirstOrDefault(a => a.CountryName == countryName).PhoneCode, expected.FirstOrDefault(a => a.CountryName == countryName).TelephoneCode);
}
You have to set up the Local property of your idbSet mock.
For example:
idbSet = new Mock<IDbSet<CountryCode>>();
var col = new ObservableCollection<CountryCode>();
idbSet.SetupGet(x => x.Local).Returns(col);
I had been using a method to create my mock sets like this:
public static Mock<IDbSet<T>> CreateMockSet<T>(IQueryable<T> data) where T : class
{
var mockSet = new Mock<IDbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
return mockSet;
}
I merely added this line:
mockSet.Setup(x => x.Local).Returns(new ObservableCollection<T>());
before the return statement and it solved my problems.
Many of my queries look like this:
var myset = context.EntitySetName.Local.SingleOrDefault(x=>x.something==something)
??
context.SingleOrDefault(x=>x.something==something);
So I just need Local to not be null so that it doesn't throw a null reference exception.

Entity Framework 4 SaveChanges not working and not throwing any error?

I am trying to use my generic repository with a "unit of work" pattern.
Here is my work details
public class GenericRepository:IRepository
{
private readonly string _connectionStringName;
private ObjectContext _objectContext;
private readonly PluralizationService _pluralizer = PluralizationService.CreateService(CultureInfo.GetCultureInfo("en"));
public GenericRepository()
{
this._objectContext = ContextManager.CurrentFor();
}
public void Add<TEntity>(TEntity entity) where TEntity : class
{
((DataEntities.MyTestDBEntities)_objectContext).Countries.AddObject(new Country() { CountryName="UGANDA"});
this._objectContext.AddObject(GetEntityName<TEntity>(), entity);
}
public void Update<TEntity>(TEntity entity) where TEntity : class
{
var fqen = GetEntityName<TEntity>();
object originalItem;
EntityKey key = ObjectContext.CreateEntityKey(fqen, entity);
if (ObjectContext.TryGetObjectByKey(key, out originalItem))
{
ObjectContext.ApplyCurrentValues(key.EntitySetName, entity);
}
}
private string GetEntityName<TEntity>() where TEntity : class
{
return string.Format("{0}.{1}", ObjectContext.DefaultContainerName, _pluralizer.Pluralize(typeof(TEntity).Name));
}
public object Get<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return ObjectContext.CreateQuery<TEntity>(entityName);
}
public IEnumerable<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class
{
return GetQuery<TEntity>().Where(criteria);
}
private IUnitOfWork unitOfWork;
public ObjectContext ObjectContext
{
get { return ContextManager.CurrentFor(); }
}
public IUnitOfWork UnitOfWork
{
get
{
if (unitOfWork == null)
{
unitOfWork = new UnitOfWork(this.ObjectContext);
}
return unitOfWork;
}
}
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return ObjectContext.CreateQuery<TEntity>(entityName);
}
}
then I will redirect save changes and other committing the transaction with UnitOfWork.cs
public class UnitOfWork:IUnitOfWork
{
private DbTransaction _transaction;
private ObjectContext _objectContext;
public UnitOfWork(ObjectContext context)
{
_objectContext = context;
}
public bool IsInTransaction
{
get { return _transaction != null; }
}
public void BeginTransaction()
{
BeginTransaction(IsolationLevel.ReadCommitted);
}
public void BeginTransaction(IsolationLevel isolationLevel)
{
if (_transaction != null)
{
throw new ApplicationException("Cannot begin a new transaction while an existing transaction is still running. " +
"Please commit or rollback the existing transaction before starting a new one.");
}
OpenConnection();
_transaction = _objectContext.Connection.BeginTransaction(isolationLevel);
}
public void RollBackTransaction()
{
if (_transaction == null)
{
throw new ApplicationException("Cannot roll back a transaction while there is no transaction running.");
}
try
{
_transaction.Rollback();
}
catch
{
throw;
}
finally
{
ReleaseCurrentTransaction();
}
}
public void CommitTransaction()
{
if (_transaction == null)
{
throw new ApplicationException("Cannot roll back a transaction while there is no transaction running.");
}
try
{
_objectContext.SaveChanges();
_transaction.Commit();
}
catch
{
_transaction.Rollback();
throw;
}
finally
{
ReleaseCurrentTransaction();
}
}
public void SaveChanges()
{
if (IsInTransaction)
{
throw new ApplicationException("A transaction is running. Call BeginTransaction instead.");
}
_objectContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
}
public void SaveChanges(SaveOptions saveOptions)
{
if (IsInTransaction)
{
throw new ApplicationException("A transaction is running. Call BeginTransaction instead.");
}
_objectContext.SaveChanges(saveOptions);
}
/// <summary>
/// Releases the current transaction
/// </summary>
private void ReleaseCurrentTransaction()
{
if (_transaction != null)
{
_transaction.Dispose();
_transaction = null;
}
}
private void OpenConnection()
{
if (_objectContext.Connection.State != ConnectionState.Open)
{
_objectContext.Connection.Open();
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes the managed and unmanaged resources.
/// </summary>
/// <param name="disposing"></param>
private void Dispose(bool disposing)
{
if (!disposing)
return;
if (_disposed)
return;
ReleaseCurrentTransaction();
_disposed = true;
}
private bool _disposed;
}
and I am getting my context through my ContextManager class:
public class ContextManager
{
/// <summary>
/// The default connection string name used if only one database is being communicated with.
/// </summary>
public static readonly string DefaultConnectionStringName = "DefaultDb";
/// <summary>
/// An application-specific implementation of IObjectContextStorage must be setup either thru
/// <see cref="InitStorage" /> or one of the <see cref="Init" /> overloads.
/// </summary>
private static IObjectContextStorage Storage { get; set; }
/// <summary>
/// Maintains a dictionary of object context builders, one per database. The key is a
/// connection string name used to look up the associated database, and used to decorate respective
/// repositories. If only one database is being used, this dictionary contains a single
/// factory with a key of <see cref="DefaultConnectionStringName" />.
/// </summary>
// private static Dictionary<string, IObjectContextBuilder<ObjectContext>> objectContextBuilders = new Dictionary<string, IObjectContextBuilder<ObjectContext>>();
private static object _syncLock = new object();
/// <summary>
/// Used to get the current object context session if you're communicating with a single database.
/// When communicating with multiple databases, invoke <see cref="CurrentFor()" /> instead.
/// </summary>
public static ObjectContext Current
{
get { return CurrentFor(); }
}
/// <summary>
/// Used to get the current ObjectContext associated with a key; i.e., the key
/// associated with an object context for a specific database.
///
/// If you're only communicating with one database, you should call <see cref="Current" /> instead,
/// although you're certainly welcome to call this if you have the key available.
/// </summary>
public static ObjectContext CurrentFor()
{
ObjectContext context = null;
lock (_syncLock)
{
if (context == null)
{
context =new TestDAL.DataEntities.MyTestDBEntities();
//Storage.SetObjectContextForKey(key, context);
}
}
return context;
}
/// <summary>
/// This method is used by application-specific object context storage implementations
/// and unit tests. Its job is to walk thru existing cached object context(s) and Close() each one.
/// </summary>
public static void CloseAllObjectContexts()
{
if (CurrentFor().Connection.State == System.Data.ConnectionState.Open)
{
CurrentFor().Connection.Close();
}
}
}
it gives me retrieval of entities, but when I want to create an entity it doesn't shows nay error nor any update in the database.
Any clue will be helpful.
Your public static ObjectContext CurrentFor() method will always create a new context. And your queries are using the ObjectContext property
public ObjectContext ObjectContext
{
get { return ContextManager.CurrentFor(); }
}
Hence you are using multiple instances of ObjectContext. You are calling SaveChanges() of a different instance of ObjectContext. So no changes will be persisted.
Do not handle the transactions explicitly as you did in UnitOfWork. The ObjectContext will do that part.
Your design is a complicated abstraction. Try to use the framework as it is or find a simple Repository pattern which has already being tested an used.