Automapper ValueResolver with dependency resolved via StructureMap - c#

This is what I am currently using (simplified and run in console app):
public class SomeValueResolver : ValueResolver<DateTime, long>
{
private readonly ISomeDependency _someDependency;
public SomeValueResolver(ISomeDependency _someDependency)
{
// ...
}
protected override long ResolveCore(DateTime source)
{
// ...
}
}
public class MyRegistry : Registry
{
public MyRegistry()
{
For<ISomeDependency >()
.Singleton()
.Use<SomeDependency>();
}
}
public static class AutoMapperConfiguration
{
public static void Configure(IContainer container)
{
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(t => container.GetInstance(t));
cfg.AddProfile(new AutomapperProfile1());
});
}
}
public class AutomapperProfile1 : Profile
{
protected override void Configure()
{
CreateMap<Source, Target>()
.ForMember(dest => dest.Y, opt => opt.ResolveUsing<SomeValueResolver>().FromMember(e => e.X))
.IgnoreAllSourcePropertiesWithAnInaccessibleSetter();
}
}
public class Source
{
public DateTime X { get; set; }
}
public class Target
{
public DateTime Y { get; set; }
}
// main method
var container1 = new Container(new MyRegistry());
AutoMapperConfiguration.Configure(container1);
var source = new Source { X = DateTime.UtcNow };
var target = Mapper.Map<Target>(source);
Unfortunately, I get an exception along those lines:
Unable to create a build plan for concrete type SomeValueResolver
new SomeValueResolver(ISomeDependency)
? ISomeDependency= **Default**
1.) Attempting to create a BuildPlan for Instance of SomeValueResolver -- SomeValueResolver
2.) Container.GetInstance(SomeValueResolver)
Can this be resolved (pardon the pun).

I've tried your code with StructureMap 4.0.1.318 and Automapper 4.2.0.0.
I did get an exception which is different because related to bad conversion of DateTime to Int64.
I think you intended to write this :
public class Target
{
public long Y { get; set; }
}
By changing the type, the mapping works like a charm.
It's maybe related to the SomeDependency class which should possess a parameterless constructor to be resolved that way.

Related

OData ignore certain properties unless explicitly stated to be returned

I have this model with following attributes. (Simplified)
public class Blog {
private string Code { get; set; }
private string Name { get; set; }
private byte[] Image { get; set; }
}
When I make a request to the OData URL for ex: http://localhost/api/odata/Blog, I want only Code and Name properties to be returned, ignoring the Image. And if I make
a request something like http://localhost/api/odata/Blog?$select=(Code,Name,Image) then I want the Image to be returned. How can I make this work?
Using attributes like [IgnoreDataMember] makes it unavailable for OData query to be accessed, therefore it is not a suitable solution.
First, probably properties of the Blog class are public, not private.
I had a similar scenario and resolve it by implementing a custom serializer:
Serializer provider class:
public class MyODataSerializerProvider : DefaultODataSerializerProvider
{
MyResourceSerializer myResourceSerializer;
public MyODataSerializerProvider(IServiceProvider serviceProvider) : base(serviceProvider)
{
myResourceSerializer = new MyResourceSerializer(this);
}
public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsEntity())
{
return myResourceSerializer;
}
return base.GetEdmTypeSerializer(edmType);
}
}
Serializer class:
public class MyResourceSerializer : ODataResourceSerializer
{
public MyResourceSerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider) { }
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
var resource = base.CreateResource(selectExpandNode, resourceContext);
if (selectExpandNode.SelectAllDynamicProperties)
{
resource.Properties = resource.Properties.Where(p => p.Name != "Image");
}
return resource;
}
}
And configuration of course:
routeBuilder.MapODataServiceRoute("OData", "odata", b =>
{
b.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => edmModel);
var conventions = ODataRoutingConventions.CreateDefault();
//Workaround for https://github.com/OData/WebApi/issues/1622
conventions.Insert(0, new AttributeRoutingConvention("OData", app.ApplicationServices, new DefaultODataPathHandler()));
//Custom Convention
b.AddService<IEnumerable<IODataRoutingConvention>>(Microsoft.OData.ServiceLifetime.Singleton, a => conventions);
b.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataSerializerProvider), sp => new MyODataSerializerProvider(sp));
});

How to map two different Interface such that one Interface value get change automatically other should get reflected

I have Core in which Interface is declared as
public interface IRequestProvider
{
int SomeId { get; set; }
}
Implementation also define in same layer
and then I have another layer Repo layer in which I am calling another external nuget packages called DataAccess layer
in which I have declared
public interface IRequestProvider
{
int SomeId { get; set; }
int SomeOtherId { get; set; }
}
so In core and DataAccess both layer I have defined IRequestProvider
Lamar code
public static class SomeRegistry
{
public static void RegisterDISome(this ServiceRegistry services, IConfigurationRoot configurationRoot)
{
services.For<IRequestProvider>().Use<RequestProvider>().Scoped();
services.For<DataAccessInterfaces.IRequestProvider>().Use<DataAccessModel.RequestProvider>().Scoped();
}
}
Scoped use to pass the same instance throughout the request
Automapper is enable
public class DomainToRepoMappingsProfile : Profile
{
public DomainToRepoMappingsProfile()
{
this.CreateMap<IRequestProvider, DataAccess.IRequestProvider>()
.ForMember(dst => dst.SomeOtherId, opt => opt.Ignore());
}
}
My expectation is when I change something in Core.IRequestProvider from any layer it should auto reflected in DataAccess.IRequestProvider layer
Currently I am calling IDomainToRepoMappingRequestProvider.map() each time to set DataAccess.IRequestProvider
public class DomainToRepoMappingRequestProvider : IDomainToRepoMappingRequestProvider
{
private readonly IMapper _mapper = null;
private readonly IRequestProvider _requestProvider = null;
private DataAccess.IRequestProvider _dataAccessRequestProvider = null;
public DomainToRepoMappingRequestProvider(IRequestProvider requestProvider, DataAccess.IRequestProvider dataAccessRequestProvider, IMapper mapper)
{
_mapper = mapper;
_requestProvider = requestProvider;
_dataAccessRequestProvider = dataAccessRequestProvider;
}
public void Map()
{
_mapper.Map(_requestProvider, _dataAccessRequestProvider);
}
}
I finding a solution to reflect changes automatically when something is changed without calling map()
How about having a property setter in the implementation of IRequestProvider call the mapper for you? The property getters and setters can be used to do much more than just setting a private backing field. An example:
public class RequestProvider : IRequestProvider
{
private readonly _mappingProvider;
private int _someId;
public RequestProvider(IDomainToRepoMappingRequestProvider mappingProvider)
{
_mappingProvider = mappingProvider
}
public int SomeId
{
get;
set
{
_someId = value;
_mappingProvider.Map();
}
}
}

C# Automapper How to resolve using property from customresolver

I am using the following mapping to map my data object to viewmodel object.
ObjectMapper.cs
public static class ObjectMapper
{
public static void Configure()
{
Mapper.CreateMap<User, UserViewModel>()
.ForMember(dest => dest.Title,
opt => opt.ResolveUsing<TitleValueResolver>())
.ForMember(dest => dest.Name,
opt => opt.ResolveUsing<NameValueResolver >())
.ForMember(dest => dest.ShortName,
opt => opt.ResolveUsing<ShortNameValueResolver >());
}
}
Parser
public class Parser{
public string GetTitle(string title){
/* add some logic */
return title;
}
public string GetName(string title){
/* add some logic */
return name;
}
public string GetShortName(string title){
/* add some logic */
return shortname;
}
}
AutoMapperCustomResolvers.cs
public class TitleValueResolver : ValueResolver<User, string>
{
private readonly BaseValueResolver _baseResolver;
public TitleValueResolver()
{
_baseResolver = new BaseValueResolver();
}
protected override string ResolveCore(Usersource)
{
return _baseResolver.Parser.GetTitle(source.TITLE);
}
}
public class NameValueResolver : ValueResolver<User, string>
{
private readonly BaseValueResolver _baseResolver;
public NameValueResolver()
{
_baseResolver = new BaseValueResolver();
}
protected override string ResolveCore(Usersource)
{
return _baseResolver.Parser.GetName(source.TITLE);
}
}
public class ShortNameValueResolver : ValueResolver<User, string>
{
private readonly BaseValueResolver _baseResolver;
public ShortNameValueResolver()
{
_baseResolver = new BaseValueResolver();
}
protected override string ResolveCore(Usersource)
{
return _baseResolver.Parser.GetShortName(source.TITLE);
}
}
I am using the above code to add logic to the destination property using the separate custom value resolvers. Not sure is this the right approach.
i) Is there a better way to achieve this?
ii) And how to use unity to resolve in case i want to inject some dependency to custom resolver constructor?
Thanks
As I understand your question, you want to utilize a ValueResolver, that resolves multiple source properties into an intermediate data object, which is used to resolve multiple target properties. As an example, I assume the following source, target, intermediate and resolver types:
// source
class User
{
public string UserTitle { get; set; }
}
// target
class UserViewModel
{
public string VM_Title { get; set; }
public string VM_OtherValue { get; set; }
}
// intermediate from ValueResolver
class UserTitleParserResult
{
public string TransferTitle { get; set; }
}
class TypeValueResolver : ValueResolver<User, UserTitleParserResult>
{
protected override UserTitleParserResult ResolveCore(User source)
{
return new UserTitleParserResult { TransferTitle = source.UserTitle };
}
}
You need a target property in order to utilize opt.ResolveUsing<TypeValueResolver>(). This means, you can establish a mapping, where an appropriate target property is available.
So, for the moment, lets wrap the result into an appropriate container type:
class Container<TType>
{
public TType Value { get; set; }
}
And create a mapping
Mapper.CreateMap<User, Container<UserViewModel>>()
.ForMember(d => d.Value, c => c.ResolveUsing<TypeValueResolver>());
And another mapping
Mapper.CreateMap<UserTitleParserResult, UserViewModel>()
.ForMember(d => d.VM_Title, c => c.MapFrom(s => s.TransferTitle))
.ForMember(d => d.VM_OtherValue, c => c.Ignore());
And another mapping
Mapper.CreateMap<User, UserViewModel>()
.BeforeMap((s, d) =>
{
Mapper.Map<User, Container<UserViewModel>>(s, new Container<UserViewModel> { Value = d });
})
.ForAllMembers(c => c.Ignore());
// establish more rules for properties...
The last mapping is a bit special, since it relies on a nested mapping in order to update the destination with values from source via separately configured mapping rules. You can have multiple different transfer mappings for different properties by adding appropriate intermediate mappings and calls in BeforeMap of the actual mapped type. The properties that are handled in other mappings need to be ignored, since AutoMapper doesn't know about the mapping in BeforeMap
Small usage example:
var user = new User() { UserTitle = "User 1" };
// create by mapping
UserViewModel vm1 = Mapper.Map<UserViewModel>(user);
UserViewModel vm2 = new UserViewModel() { VM_Title = "Title 2", VM_OtherValue = "Value 2" };
// map source properties into existing target
Mapper.Map(user, vm2);
Dunno if this helps you. There might be better ways if you rephrase your question to describe your initial problem instead of what you suspect to be a solution.

Fluent Nhibernate : How to make Search Class Generic in best possible way

I have a class say 'AllInvoices', the structure of which is as below :
public class ActiveInvoices
{
public string InvoiceId { get; set; }
public string InvoiceIssueDate { get; set; }
public string InvoiceTransactionDate { get; set; }
public string InvoiceExpiryDate { get; set; }
}
The mapping class for Entity ActiveInvoices is
public class ActiveInvoicesMap : ClassMap<ActiveInvoices>
{
public ActiveInvoicesMap()
{
Id(x => x.InvoiceId);
Map(x => x.InvoiceIssueDate);
Map(x => x.InvoiceTransactionDate);
Map(x => x.InvoiceExpiryDate);
}
}
Now with this entity I search for Active Invoices in database with the following class
public class SearchInvoices
{
public readonly IRepository<ActiveInvoices> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<ActiveInvoices> activeInvoicesRepository)
{
latestActiveInvoicesRepository = activeInvoicesRepository;
}
public List<ActiveInvoices> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
To Search Active Invoices I call the Search Class method 'GetActiveInvoices()' from a workflow class which looks like below :
public class CurrentWorkFlow
{
public void GetActiveInvoices()
{
var invoiceSearch = new SearchInvoices(IRepository <ActiveInvoices> repository);
}
}
Now the issue in hand is that I need to make class 'SearchInvoices' generic to support all other possible types that i would create like 'ExpiredInvoices', 'ArchivedInvoices', 'FutureInvoices' etc and not just only for type 'ActiveInvoices'.
These new types may or may not have the same structure as 'ActiveInvoices'.
I have tried to use dynamic but thought of asking experts around here if they have any better ideas to implement the required functionality
in most optimized generic manner.
Regrets for being very detailed and lengthy in asking but i thought to include as many details as i can. Hope it goes well with you folks.
Couldn't you make a generic repository like this? -
interface IDomain{
}
class ExpiredInvoices: IDomain{
}
class ActiveInvoices: IDomain{
}
interface IRepository{
}
class Repsoitory: IRepository {
public static IList<T> Get<T>() where T: IDomain //default one
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().ToList();
}
}
public static IList<T> Get<T>(Expression<Func<T, bool>> expression) where T: IDomain // overloaded get with linq predicate
{
using (ISession session = OpenEngineSession())
{
return session.Query<T>().Where(expression).ToList();
}
}
}
Then use it like -
var repo = // get IRepository
var activeInvoices = repo.Get<ActiveInvoices>();
var expiredInvoices = repo.Get<ExpiredInvoices>();
EDIT: As Repository cannot be changed, suggested by OP
If you cannot change the repository, then I would suggest making the search service interface dependent, rather than concrete class -
interface IInvoice{
}
class ExpiredInvoices: IInvoice{
}
class ActiveInvoices: IInvoice{
}
public class SearchInvoices
{
public readonly IRepository<IInvoice> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<IInvoice> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices<T>() where T: IInvoice
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
Then call like -
var ss = new SearchService(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices<ActiveInvoices>();
Or,
public class SearchInvoices<T> where T: IInvoice
{
public readonly IRepository<T> latestActiveInvoicesRepository;
public SearchInvoices(IRepository<T> activeInvoicesRepository)
{
latestInvoicesRepository = activeInvoicesRepository;
}
public List<T> GetActiveInvoices()
{
var listOfActiveInvoices = latestActiveInvoicesRepository.GetAll();
return listOfActiveInvoices;
}
}
then call like -
var ss = new SearchService<ActiveInvoices>(IRepository <ActiveInvoices> repository);
var items = ss.GetActiveInvoices();
Whichever suits you.

DbContext has been disposed when using Ninject

I'm still getting error like this:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code.
Additional information: The operation cannot be completed because the DbContext has been disposed.
I'm using Ninject and when I use injected repository (InRequestScope) to HomeController everything work good, but when I use injected class InSingletonScope, which has another repository injected by InRequestScope, then I get this error.
My InSingletonScope class:
public class SettingsManager : ISettingsManager
{
private readonly IConfigurationRepository _configurationRepository;
private readonly Lazy<ApplicationSettings> _applicationSettings;
public ApplicationSettings Application { get { return _applicationSettings.Value; } }
private SettingsManager(IConfigurationRepositorycontext)
{
_configurationService = context;
_applicationSettings = new Lazy<ApplicationSettings>(() => new ApplicationSettings(context));
}
}
ApplicationSettings class:
public class ApplicationSettings : ApplicationSettingsBase
{
private readonly IConfigurationRepository _configurationRepository;
public ApplicationSettings(IConfigurationRepository context)
{
_configurationRepository= context;
}
public string GetItem()
{
return _configurationService.GetApplicationConfiguration(4).First().Value.ToString();
}
}
My ConfigurationRepository:
public class ConfigurationRepository : BaseRepository<Configuration>, IConfigurationRepository
{
public ConfigurationRepository(DbContext _dbContext)
: base(_dbContext)
{
}
public IQueryable<ConfigurationDTO> GetApplicationConfiguration(int domainId)
{
return _dbContext.Set<Configuration>()
.Where(x => x.DomainId == 5)
.Select(x => new ConfigurationDTO
{
Name = x.Name,
Value = x.Value
});
}
}
And in this repository I get an error.
My NinjectWebCommon.RegisterServices method:
kernel.Bind<ISettingsManager>().To<SettingsManager>().InSingletonScope();
kernel.Bind<IConfigurationRepository>().To<ConfigurationRepository>().InRequestScope();
kernel.Bind<DbContext>().To<EntitiesDbContext>().InRequestScope();
Where could be the problem?
EDIT
The problem disappears when I change DbContext to EntitiesDbContext:
public class ConfigurationRepository : BaseRepository<Configuration>, IConfigurationRepository
{
public ConfigurationRepository(EntitiesDbContext _dbContext)
: base(_dbContext)
{
}
}
So my binding in Ninject is wrong?
kernel.Bind<DbContext>().To<EntitiesDbContext>().InRequestScope();
Why?
I have new model:
public partial class EntitiesDbContext : DbContext
{
public EntitiesDbContext ()
: base("name=EntitiesDbContext ")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Configuration> Configuration { get; set; }
}
}

Categories

Resources