Use Automapper in ITypeConverter - c#

I'm upgrading AutoMapper in a project, converting from the static Mapper.CreateMap to the new way and injecting a IMapper where I need to map.
This is going great except for one use case. I have several ITypeConverters for complex mapping which are using the Mapper.Map function. How can I fix this? Below is the code I'm using at the moment.
The static Mapper.Map can't find my defined mappings because the're not being created using the static method.
public partial class ApplicationMappingsProfile
{
private void RegisterMappings()
{
CreateMap<Application, AppDto>()
.ConvertUsing<ApplicationTypeConverter>();
}
}
private class ApplicationTypeConverter : ITypeConverter<App, AppDto>
{
public AppDto Convert(ResolutionContext context)
{
var src = context.SourceValue as App;
if (src == null)
{
return null;
}
var dto = Mapper.Map<App, AppDto>(src);
dto.property = Mapper.Map<Property>(src.SomeProperty);
return result;
}
}

The ResolutionContext contains a reference to the current Mapping engine. Switch the Mapper.Map with context.Engine.Mapper.Map and you're good to go.
public partial class ApplicationMappingsProfile
{
private void RegisterMappings()
{
CreateMap<Application, AppDto>()
.ConvertUsing<ApplicationTypeConverter>();
}
}
private class ApplicationTypeConverter : ITypeConverter<App, AppDto>
{
public AppDto Convert(ResolutionContext context)
{
var src = context.SourceValue as App;
if (src == null)
{
return null;
}
var dto = Mapper.Map<App, AppDto>(src);
dto.property = context.Engine.Mapper.Map.Map<Property>(src.SomeProperty);
return result;
}
}

Related

How to access dbContext in a singleton-class?

I am currently accessing my database directly when I get a GET-request by using something like this: _context.EXT_PRAMEX_INSERTS.Where(item => item.MatID == MaterialID.
But my database does not change very often so I want to create a data-class that fetches all tables on startup into lists.
And then I just parse the lists when I need to get any of the entries.
I was thinking that I could create a singleton-class that fetches all data on startup and then I just use that instance to get my data. But how do I access the context inside the singleton ? Or is there a better way to accomplish what I am trying to do ?
public sealed class ExternalDatabase
{
private static ExternalDatabase _instance = null;
private static readonly object _instanceLock = new object();
private List<EXT_PramexInserts>? pramexInserts;
private List<EXT_PrototypeEndmills>? prototypeEndmills;
private static List<IProducts> extAll = new List<IProducts>();
ExternalDatabase()
{
pramexInserts = pramexInserts == null ? _context.Set<EXT_PramexInserts>().ToList() : pramexInserts;
prototypeEndmills = prototypeEndmills == null ? _context.Set<EXT_PrototypeEndmills>().ToList() : prototypeEndmills;
if (extAll.Count == 0)
{
extAll = extAll.Union(pramexInserts).ToList().Union(prototypeEndmills).ToList();
}
}
public static ExternalDatabase Instance
{
get
{
lock (_instanceLock)
{
if (_instance == null)
{
_instance = new ExternalDatabase();
}
return _instance;
}
}
}
public List<IProducts> GetExtraData(string materialid)
{
var result = extAll.FindAll(p => p.MaterialID == materialid);
return result;
}
}
[ApiController]
[Route("DB")]
public class EXT_TablesController : ControllerBase
{
private readonly Context _context;
private static ExternalDatabase data = ExternalDatabase.Instance;
public EXT_TablesController(Context context)
{
_context = context;
}
//...
[HttpPost]
public IEnumerable<IProducts> Post([FromBody] EXT_Request request)
{
string selectedTable = null;
var (MaterialID, Type, Brand) = request;
if (Type != null && Brand != null)
{
selectedTable = $"EXT_{Brand}_{Type}";
switch (selectedTable)
{
case "EXT_PRAMEX_INSERTS":
//var items = _context.EXT_PRAMEX_INSERTS.Where(item => item.MatID == MaterialID);
return data.GetExtraData(MaterialID);
default:
return null;
}
}
return null;
}
}
It's better to keep your DbContext short-lived.
If you want to use the context in a singleton class, you can try DbContextFactory.
Also you may want to have a look at the secondary level cache pattern. Here is a ready-to-go package.
I don't know if it is the best answer but I followed one of the tips that Mehdi Dehghani suggested in the comment above.
I created a new context inside the singleton and it solved my problem.

How do i get symbol references in a diagnostic without SymbolFinder?

Currently i've got this code:
private async Task<bool> IsMentionedInDisposeCallAsync(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax fieldDeclarationSyntax)
{
foreach (var variableDeclaratorSyntax in fieldDeclarationSyntax.Declaration.Variables)
{
var declaredSymbol = context.SemanticModel.GetDeclaredSymbol(variableDeclaratorSyntax);
if (declaredSymbol is IFieldSymbol fieldSymbol)
{
// SymbolFinder.FindReferencesAsync()
var b = fieldSymbol.Locations;
// context.SemanticModel.Compilation.
}
}
return false;
}
And this scenario:
private static readonly string TestSourceImplementsDisposableAndDoesMentionDisposableField = #"
using System;
using System.IO;
namespace ConsoleApplication1
{
public class SampleDisposable : IDisposable
{
public void Dispose()
{
}
}
public class SampleConsumer : IDisposable
{
private SampleDisposable _disposable = new SampleDisposable();
private IDisposable _ms = new MemoryStream();
public void Dispose()
{
_disposable?.Dispose();
_ms?.Dispose();
}
}
}";
Ultimately my desire is to figure out whether a dispose method is accessing a disposable field. Unfortunately i can't seem to find a way to get this working without using SymbolFinder, which requires a solution.
I did something similar with SymbolFinder and it was an easy thing to do - but how do i do it from the functionality available within a diagnostic?
Am i missing something obvious here?
You could simply use the SemanticModel to analyse the type used for the field like this:
private async Task<bool> IsMentionedInDisposeCallAsync(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax fieldDeclarationSyntax)
{
foreach (var variableDeclaratorSyntax in fieldDeclarationSyntax.Declaration.Variables)
{
var declaredSymbol = context.SemanticModel.GetDeclaredSymbol(variableDeclaratorSyntax);
if (declaredSymbol is IFieldSymbol fieldSymbol)
{
var isDisposeable = CheckIsTypeIDisposeable(fieldSymbol.Type as INamedTypeSymbol);
// SymbolFinder.FindReferencesAsync()
var b = fieldSymbol.Locations;
// context.SemanticModel.Compilation.
}
}
return false;
}
private string fullQualifiedAssemblyNameOfIDisposeable = typeof(IDisposable).AssemblyQualifiedName;
private bool CheckIsTypeIDisposeable(INamedTypeSymbol type)
{
// Identify the IDisposable class. You can use any method to do this here
// A type.ToDisplayString() == "System.IDisposable" might do it for you
if(fullQualifiedAssemblyNameOfIDisposeable ==
type.ToDisplayString() + ", " + type.ContainingAssembly.ToDisplayString())
{
return true;
}
if(type.BaseType != null)
{
if (CheckIsTypeIDisposeable(type.BaseType))
{
return true;
}
}
foreach(var #interface in type.AllInterfaces)
{
if (CheckIsTypeIDisposeable(#interface))
{
return true;
}
}
return false;
}
Basically you would search through all interfaces of the class and the base class recursively to find the type corresponding to IDisposeable - which should be somewhere in the hierarchy.

WCF Custom OperationConext Lifetimemanager for EF DbContext

container.RegisterType<IDataContextFactory<MyDataContext>, DefaultDataContextFactory<MyDataContext>>(new PerRequestLifetimeManager());
Created a PerRequestLifetimeManager using OperationContext but it does not seem call setValue function at all, it always trys to go to GetValue() function which always retruns null since nothing has been set.
My goal is to create a lifetimeManager for dbconetxt that will give me a new dbContext per method call. transient is not an option since it won;t work for join query.
public class WcfOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private WcfOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static WcfOperationContext Current
{
get
{
WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
if (context == null)
{
context = new WcfOperationContext();
OperationContext.Current.Extensions.Add(context);
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
public class PerRequestLifetimeManager : LifetimeManager
{
private string key;
public PerRequestLifetimeManager()
{
key = Guid.NewGuid().ToString();
}
public override object GetValue()
{
if (WcfOperationContext.Current == null)
{
return null;
}
else
{
return WcfOperationContext.Current.Items[key];
}
}
public override void RemoveValue()
{
if (WcfOperationContext.Current != null)
{
WcfOperationContext.Current.Items.Remove(key);
}
}
public override void SetValue(object newValue)
{
if (WcfOperationContext.Current != null)
{
WcfOperationContext.Current.Items.Add(key, newValue);
}
}
}
My solution for this was to use this nuget package: UnityWCF
The Service should be instantiated by Unity and new instance per call.
For this use this settings on the service:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ...
Inject DbContext where you need. And register in Unity like this:
container.RegisterType<DbContext, YourDbContext>(new HierarchicalLifetimeManager(), ...);

Invoking a different constructor with autofixture [duplicate]

I'm using AutoFixture and I'd like to use a specific constructor.
I have the following code and I like to select the constructor with ITemplateParameterHandler.
public sealed class TemplateSegmentHandler : ITemplateSegmentHandler
{
public TemplateSegmentHandler(ITemplateIterator iterator)
: this(new TemplateParameterHandler(iterator))
{
Contract.Requires(iterator != null);
}
public TemplateSegmentHandler(ITemplateParameterHandler parameterHandler)
{
Contract.Requires(parameterHandler != null);
_parameterHandler = parameterHandler;
_parameterHandler.Ending += EndingParameter;
}
// ...
}
EDIT:
I want to inject the following fake implementation. (I'm using NSubstitute to create the fake object.)
public sealed class CustomTemplateParameter : ICustomization
{
private readonly ITemplateParameterHandler _context;
public CustomTemplateParameter()
{
_context = Substitute.For<ITemplateParameterHandler>();
}
public void Customize(IFixture fixture)
{
fixture.Customize<ITemplateParameterHandler>(c => c.FromFactory(() => _context));
}
public CustomTemplateParameter SetCatchAll(bool isCatchAll)
{
_context.IsCatchAll.Returns(isCatchAll);
return this;
}
}
Here is the way I'm trying to use it.
[Fact]
public void Should_return_true_when_the_segment_has_a_catch_all_parameter()
{
TemplateSegmentHandler segmentHandler = new Fixture().Customize(new TemplateSegmentHandlerFixture())
.Customize(new CustomTemplateParameterHandler()
.SetCatchAll(true))
.Create<TemplateSegmentHandler>();
segmentHandler.Parameter.Start();
segmentHandler.Parameter.End();
segmentHandler.HasCatchAll.Should().BeTrue();
}
But it still selects the wrong constructor and I'm getting the following error.
Ploeh.AutoFixture.ObjectCreationExceptionAutoFixture was unable to create an instance from Somia.Web.Routing.Template.ITemplateIterator, most likely because it has no public constructor, is an abstract or non-public type.
Request path:
Somia.Web.Routing.Template.TemplateSegmentHandler -->
Somia.Web.Routing.Template.ITemplateIterator iterator -->
Somia.Web.Routing.Template.ITemplateIterator
I ended up implementing IMethodQuery and select the ctor I wanted.
public sealed class SelectedFirstConstructorQuery : IMethodQuery
{
private readonly Type _type;
public SelectedFirstConstructorQuery(Type type)
{
_type = type;
}
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
return from ci in type.GetConstructors()
let parameter = ci.GetParameters().First()
where parameter.ParameterType == _type
select new ConstructorMethod(ci) as IMethod;
}
}
Usage:
fixture.Customize<TemplateSegmentHandler>(c => c.FromFactory(new MethodInvoker(new SelectedFirstConstructorQuery(typeof(ITemplateParameterHandler)))));
One possible way:
var parameterHandler = fixture.Create<ITemplateParameterHandler>();
var segmentHandler = fixture.Build<TemplateSegmentHandler>()
.FromFactory(() => new TemplateSegmentHandler(parameterHandler));
fixture.Inject(segmentHandler);

C# Interface Method calls from a controller

I was just working on some application architecture and this may sound like a stupid question but please explain to me how the following works:
Interface:
public interface IMatterDAL
{
IEnumerable<Matter> GetMattersByCode(string input);
IEnumerable<Matter> GetMattersBySearch(string input);
}
Class:
public class MatterDAL : IMatterDAL
{
private readonly Database _db;
public MatterDAL(Database db)
{
_db = db;
LoadAll(); //Private Method
}
public virtual IEnumerable<Matter> GetMattersBySearch(string input)
{
//CODE
return result;
}
public virtual IEnumerable<Matter> GetMattersByCode(string input)
{
//CODE
return results;
}
Controller:
public class MatterController : ApiController
{
private readonly IMatterDAL _publishedData;
public MatterController(IMatterDAL publishedData)
{
_publishedData = publishedData;
}
[ValidateInput(false)]
public JsonResult SearchByCode(string id)
{
var searchText = id; //better name for this
var results = _publishedData.GetMattersBySearch(searchText).Select(
matter =>
new
{
MatterCode = matter.Code,
MatterName = matter.Name,
matter.ClientCode,
matter.ClientName
});
return Json(results);
}
This works, when I call my controller method from jquery and step into it, the call to the _publishedData method, goes into the class MatterDAL.
I want to know how does my controller know to go to the MatterDAL implementation of the Interface IMatterDAL. What if I have another class called MatterDAL2 which is based on the interface. How will my controller know then to call the right method?
I am sorry if this is a stupid question, this is baffling me.
EDIT:
Based on the responses, it seems like this is where the dependency is being resolved:
This is a ninject call:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ICpdMatterDAL>().To<CachedCpdData>();
}
Where CachedCpdData is:
public class CachedCpdData : ICpdMatterDAL
{
private static readonly object CacheLockObject = new object();
private readonly MatterDAL _matterData;
public CachedCpdData()
{
_matterData = DomainModel.DataAccessManager.Instance.Matters;
}
public IEnumerable<Matter> GetMattersForAutoCompleteByCode(string input)
{
var cacheKey = string.Format("matter-search-{0}", input ?? "");
var result = HttpRuntime.Cache[cacheKey] as IEnumerable<Matter>;
if (result == null)
{
lock (CacheLockObject)
{
result = HttpRuntime.Cache[cacheKey] as IEnumerable<Matter>;
if (result == null)
{
result = _matterData.GetMattersForAutoCompleteByCode(input).ToList();
HttpRuntime.Cache.Insert(cacheKey, result, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero);
}
}
}
return result;
}
public IEnumerable<Matter> GetMattersByMatterCodeSearch(string input)
{
return _matterData.GetMattersByMatterCodeSearch(input);
}
}
The rason why your code is using the right implementation of IMatterDAL is because it's being passed as a parameter in the constructor of MatterController. I'm almost sure that your code is using some Dependency Injection framework to resolve IMatterDAL.
In fact Ninject is a DI Framework. Your code should have something like
kernel.Bind<IMatterDAL>().To<MatterDAL >();

Categories

Resources