Bootstrapper.AutoMapper and Profile registration order - c#

I'm working on an ASP.NET MVC 3 application using AutoMapper 2.2.0. I have some AutoMapper profiles declared and when I initialize them manually everything works just fine.
AutoMapper.Mapper.Initialize(x =>
{
x.AddProfile<ProdutoToProdutoViewModel>();
x.AddProfile<IPagedListProdutoToIPagedListProdutoViewModel>();
x.AddProfile<ItemToItemViewModel>();
x.AddProfile<CarrinhoToCarrinhoViewModel>();
});
//This is working
But when I try to initialize them with Bootstrapper.AutoMapper 2.0.3.0...
Bootstrapper.With.AutoMapper().Start();
...a configuration exception is thrown:
The following property on eGuruShop.Web.ViewModels.ItemViewModel cannot be mapped:
Itens
Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type eGuruShop.Web.ViewModels.ItemViewModel.
Context:
Mapping to property Itens from eGuruShop.Domain.CatalogoProdutos.Item to eGuruShop.Web.ViewModels.ItemViewModel
Mapping to property Itens from System.Collections.Generic.IList`1[[eGuruShop.Domain.CatalogoProdutos.Item, eGuruShop.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] to System.Collections.Generic.IList`1[[eGuruShop.Web.ViewModels.ItemViewModel, eGuruShop.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
Mapping from type eGuruShop.Domain.CatalogoProdutos.Carrinho to eGuruShop.Web.ViewModels.CarrinhoViewModel
Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown
The CarrinhoToCarrinhoViewModel profile depends on the ItemToItemViewModel profile and when I change the initialization order to
AutoMapper.Mapper.Initialize(x =>
{
x.AddProfile<ProdutoToProdutoViewModel>();
x.AddProfile<IPagedListProdutoToIPagedListProdutoViewModel>();
x.AddProfile<CarrinhoToCarrinhoViewModel>();
x.AddProfile<ItemToItemViewModel>();
});
//Exception
I've got the same exception than before.
I suspect Bootstrapper is initializing the profiles in the wrong order, but I don't know how to solve it without abandoning Bootstrapper. Any suggestions or solutions to this problem?
Thanks

Related

Error when trying to Map List using Automapper

I need to map IReadOnlyList<Person> to IReadOnlyList<PersonResponse> using Automapper.
IReadOnlyList<Person> personList = await _personRespository.getall();
var t = MyMapper.Mapper.Map<IReadOnlyList<PersonResponse>>(personList );
Mapping Class
CreateMap<IReadOnlyList<PersonResponse>, IReadOnlyList<Person>>().ReverseMap();
The error I get:
System.TypeLoadException: Method 'get_Item' in type
'Proxy_System.Collections.Generic.IReadOnlyList`1[[App.Application.Responses.PersonResponse,
App.Application, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]34471389' from assembly 'AutoMapper.Proxies,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005'
does not have an implementation. at
System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() at
System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
Create an mapping between Person and PersonResponse, the concerned element types. Automapper would take care of collections themselves.
CreateMap<PersonResponse, Person>().ReverseMap();
You can read more Automapper and Collections here

Can't register a View and ViewModel between 2 assemblies (UWP, Splat)

Using the latest RxUI v8 preview and Splat 2.0, in a UWP project referencing a .Net Standard 2.0 library, I can't register my view and viewmodel unless they reside in the same assembly.
I have:
Locator.CurrentMutable.RegisterLazySingleton(() => new HomeView(), typeof(IViewFor<HomeViewModel>));
But Splat gives an error:
DefaultViewLocator: Failed to find type named 'RxUI.UWP.Core.Views.HomeView, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
DefaultViewLocator: Failed to resolve service for type 'ReactiveUI.IViewFor`1[[RxUI.UWP.Core.ViewModels.HomeViewModel, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
DefaultViewLocator: Failed to find type named 'ReactiveUI.IRoutableView, ReactiveUI, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null'.
DefaultViewLocator: Failed to resolve service for type 'ReactiveUI.IViewFor`1[[ReactiveUI.IRoutableViewModel, ReactiveUI, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
DefaultViewLocator: Failed to resolve view for view model type 'ReactiveUI.IRoutableViewModel'.
DefaultViewLocator: Failed to find type named 'RxUI.UWP.Core.Views.HomeView, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
So it's looking for the HomeView in the "Core" assembly, but it resides in the UWP project. Here's the structure...
I experienced the same issue with a similar environment as your. The issue resided in the DefaultViewLocator, since the view type is being renamed and resolved incorrectly to the viewmodel's assembly and namespace.
See lines 133-134 for how the view type name is determined:
var viewModelTypeName = viewModelType.AssemblyQualifiedName;
var proposedViewTypeName = this.ViewModelToViewFunc(viewModelTypeName);
Note: ViewModelToViewFunc is only a String.Replace that replaces "ViewModel" to "View" (see constructor).
To resolve this issue, my workaround was to create my own IViewLocator implementation, something like:
public class MyViewLocator : IViewLocator {
public MyViewModelLocator(Assembly viewAssembly, string viewNameSpace)
...
private IViewFor AttemptViewResolutionFor(Type viewModelType, string contract)
{
// proposed view type is now based on provided namespace + classname as modified by ViewModelToViewFunc
if (viewModelType == null) return null;
var viewModelTypeName = viewModelType.Name;
var proposedViewTypeName = _viewNamespace + "." + this.ViewModelToViewFunc(viewModelTypeName);
...
private IViewFor AttemptViewResolution(string viewTypeName, string contract)
{
try
{
// resolve view type in the assembly of the view, and not assembly of the viewmodel
var viewType = _viewAssembly.GetType(viewTypeName); // instead of Reflection.ReallyFindType(viewTypeName, throwOnFailure: false);
...
}
Finally, your custom viewlocator implementaiton must be registered with splat so that it overwrites DefaultViewLocator implementation:
Locator.CurrentMutable.RegisterConstant<IViewLocator>(new MyViewLocator(typeof(SplashView).Namespace, typeof(SplashView).Assembly));

JSON.NET error resolving type in PowerShell cmdlet

I use the following code to deserialize JSON files to .NET objects:
using (var textReader = File.OpenText(filePath))
{
var settings = new JsonSerializerSettings
{
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
TypeNameHandling = TypeNameHandling.All
};
var deserializer = JsonSerializer.CreateDefault(settings);
deserializer.Converters.Add(new StringEnumConverter());
return deserializer.Deserialize<T>(new JsonTextReader(textReader));
}
This works all quite fine when using that functionality in the context of a unit test for example. All classes are placed in several assemblies.
Now instead of using unit tests I want to control the flow of my components by PowerShell cmdlets.
I wrote an cmdlet and import the module that is still placed in the bin\Debug folder: Import-Module .\MigrationShell.dll
This assembly references all other assemblies and classes that are serialized / deserialized.
When the JSON functions are used in the PowerShell context I get the following exception:
Error resolving type specified in JSON
'System.Collections.Generic.List`1[[Migration.Data.MediaGalleryItem,
Migration]], mscorlib'. Path '$values[0].MediaGalleryItems.$type',
line 7, position 133.
So it seems that JSON.NET is not able to resolve the type that is defined in the Migration.dll when my code is being called in PowerShell context.
How can I solve this issue?
Update:
I just checked that there are no problems in resolving my custom object types. The problem seems to be the generic list. But still the error occurs only when calling the functionality in a PowerShell cmdlet context.
I found a solution for my problem. The issue hereby is the the way of how JSON.NET resolves type names. I think it's not JSON.NET fault at all because it seems so that the PowerShell domain handles the type resolving in a different way.
The point is that I needed to provide the fully qualified type name instead of the short one for serializing and deserializing.
So I changed the serializer settings to this:
var settings = new JsonSerializerSettings
{
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
TypeNameHandling = TypeNameHandling.All
};
So the JSON changed from this type declaration
"$type": "System.Collections.Generic.List`1[[Migration.Data.MediaGalleryItem, Migration]], mscorlib"
to this one
"$type": "System.Collections.Generic.List`1[[Migration.Data.MediaGalleryItem, Migration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
Everything works fine now. Thanks to Dirk for his comments :)

App.Config does cannot access section specified

http://pastebin.com/QaCCM2Zv
I have a config file in the above link, every time i try to access the section 'InventoryFactory' using this code:
var config = (ObjectFactoryConfiguration)ConfigurationManager.GetSection("InventoryFactory");
it returns an error:
An exception of type 'System.Configuration.ConfigurationErrorsException' occurred in System.Configuration.dll but was not handled in user code
Additional information: An error occurred creating the configuration section handler for InventoryFactory: Could not load type 'WDG.ObjectFactory.ObjectFactoryConfiguration' from assembly 'System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
Any idea guys? Thanks :
If you haven't done so already you probably need to set up a custom configuration section handler to parse the "InventoryFactory" section into your "ObjectFactoryConfiguration" object. The error message indicates that the runtime is trying to load the "WDG.ObjectFactory.ObjectFactoryConfiguration" class from the "System.Configuration" assembly which wouldn't contain any of your custom classes.
...Also, you want to specify the assembly in the section, if you look at the line right above yours:<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> you can see at the end there the "log4net" assembly has been specified. Try putting the name of your assembly which contains the "ObjectFactoryConfiguration" class in the type attribute as well.

WCF DataContractSerializer and XAML Namespaces

I am sending an object to a WCF service that contains a Windows Workflow definition, but the deserializer is faulting when trying to deserialize my custom activities.
This was previously working when I had the activities' namespaces defined in the form of:
xmlns:tta="clr-namespace:MyNamespace;assembly=MyAssembly"
but for maintainability reasons I have now mapped my activity namespaces to a XAML namespace using assembly attributes:
[assembly: XmlnsPrefix("http://schemas.product.com/activities/", "tta")]
[assembly: XmlnsDefinition("http://schemas.product.com/activities/", "MyNamespace")]
Thus my xaml namespace looks like: xmlns:tta="http://schemas.thacktech.com/activities/"
And my activity declared as: <tta:Naptime />
Because of this change, I now recieve NetDispatcherFaultException which reads:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:job. The InnerException message was 'Element 'http://schemas.datacontract.org/2004/07/System.Activities:Activity' contains data from a type that maps to the name 'Naptime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null:MyNamespace.Naptime'. The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name 'MyNamespace.Naptime' and namespace 'Naptime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.'. Please see InnerException for more details.
Questions:
Why does the deseralizer succeed with type resolution when using the clr-namespace syntax, but fail when using the url-style syntax for a namespace declaration?
It looks like the type resolver is completely misinterpreting the type, listing the class name as the namespace. Why would it do this?
How do I properly implement this?
Thanks!

Categories