Xamarin iOS Linker causing AutoMapper issues - ios

I am working on a Xamarin project that is using AutoMapper. When linking is set to "Link Framework SDKs Only" I get the following error when initializing the maps
System.ArgumentNullException: Value cannot be null. Parameter name:
method
The exception is not much to go on and neither is the callstack
AutoMapper.Mappers.ConvertMapper.MapExpression
AutoMapper.Execution.TypeMapPlanBuilder.ObjectMapperExpression
AutoMapper.Execution.TypeMapPlanBuilder.MapExpression
AutoMapper.Mappers.NullableSourceMapper.MapExpression
AutoMapper.Execution.TypeMapPlanBuilder.ObjectMapperExpression
AutoMapper.Execution.TypeMapPlanBuilder.MapExpression
AutoMapper.Execution.TypeMapPlanBuilder.MapExpression
AutoMapper.Execution.TypeMapPlanBuilder.CreatePropertyMapFunc
AutoMapper.Execution.TypeMapPlanBuilder.CreatePropertyMapFunc
AutoMapper.Execution.TypeMapPlanBuilder.TryPropertyMap
AutoMapper.Execution.TypeMapPlanBuilder.CreateAssignmentFunc
AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda
AutoMapper.TypeMap.Seal AutoMapper.MapperConfiguration.Seal
AutoMapper.MapperConfiguration..ctor
AutoMapper.MapperConfiguration..ctor AutoMapper.Mapper.Initialize
The initial reading of that suggests that the Linker is simply removing some properties or indeed methods from some class we are using.
However, after commenting out most of the mappings and then reintroducing them one at a time I find that this class is currently causing the error.
[Preserve]
internal class ItemBase : CareRecordItemBase
{
[Preserve]
public string Topic { get; set; }
[Preserve]
public string InPractice { get; set; }
[Preserve]
public string PrivateVal { get; set; }
}
If I comment out the InPractice property the exception does not get thrown. This makes no sense to me. Can anyone explain why this might be a problem?
Are there better ways of diagnosing these issues?

Based on Pat's Answer:
Add an XML file LinkDescription.xml, you can name it anything you want.
Add this code:
<linker>
<assembly fullname="mscorlib">
<type fullname="System.Convert" preserve="All" />
</assembly>
</linker>
Set the file's build action to LinkDescription

See comment from AutoMapper author Lucian Bargaoanu. I needed to include an xml file that adds configuration to the Linking process.
Lucian refers to this Automapper Issue, https://github.com/AutoMapper/AutoMapper/issues/2272
Also see
Custom Linker configuration

Related

Glass Mapper loads collections only for interfaces

Using Sitecore 10.2 and Glass Mapper 5.8.180
After upgrade from Sitecore 8.2 and switching to above mentioned version of Glass Mapper our code stopped loading collection references. I am aware that in Glass Mapper now the lazy loading is turned on by default and I want to keep this setting.
Problem is with follows:
Having
[SitecoreType(TemplateId = "{...}", AutoMap = true)]
public interface IStatementContainer
{
IEnumerable<Statement> Statements { get; set; }
}
public class StatementContainer : IStatementContainer
{
public virtual IEnumerable<Statement> Statements { get; set; }
}
The following code
_mvcContext.SitecoreService.GetItem<StatementContainer>(datasource)
does not work properly. The Statements are empty.
For following code
_mvcContext.SitecoreService.GetItem<IStatementContainer>(datasource)
the Statements are being loaded properly.
Could you explain me the difference in behavior?
Our legacy code contains a lot of usages of concrete types rather than interfaces, changing all of them would be difficult.

Error when using MvxAppCompatActivity

I am writing an application with Xamarin.Android with MvvmCross. I want my Activity to inherit from MvxAppCompatActivity so that I can use fragments. Here is my base class:
public class BaseActivity<TViewModel> : MvxAppCompatActivity<TViewModel> where TViewModel : MvxViewModel
{
public new TViewModel ViewModel
{
get { return base.ViewModel; }
set { base.ViewModel = value; }
}
}
I get this error on the OnCreate of my Activity:
Failed resolution of: Landroid/support/v7/appcompat/R$drawable; Didn't
find class "android.support.v7.appcompat.R$drawable" on path:
DexPathList...
But if I change MvxAppCompatActivity to MvxActivity it works fine...why?
I downloaded your solution and tried to build the Android project. It fails with 18 occurrences of the same error:
error: No resource identifier found for attribute 'loginButtonBackgroundColor' in package ...
So after a little inspection of your solution, I did the following steps to solve your issue:
1) In login_screen.axml I saw you had this line:
xmlns:[YOURNAMESPACE]="http://schemas.android.com/apk/res/[YOUR PACKAGE]"
Which is unnecessary. After removing it, and changing the lines [YOURNAMESPACE]:loginButtonBackgroundColor=... to local:loginButtonBackgroundColor=... the build succeeds.
2) I saw some layout files are located inside the /drawable folder (button_round_corner.xml, input_box.xml and login_button.xml). I moved them to the /layout folder and fixed the issues the change produced (only two).
3) Made Setup class inherit from MvxAppCompatSetup.
4) Added a RegisterAttribute over the LoginButton control. So the class definition looks like this:
using Android.Runtime;
...
namespace Xxx.Droid.Components
{
[Register(nameof(LoginButton))]
public class LoginButton : FrameLayout, IMvxNotifyPropertyChanged
{
...
}
}
And that's it! Probably (2) was not necessary, but leaving it here just in case.
It could be several things but it is probably the lack of some android support packages. Mainly the lack of Xamarin.Android.Support.Design gives that error. So check if you have that added and if not add it and it should solve your problem.
If it doesn't it's highly likely you lack some other android support packages

MvvmCross vNext: ObservableColletion is defined in an assembly that is not referenced

I have got my PCL model to build now, which took a bit of time making plug-ins, however now in my Android UI project I get two errors when building it.
First error is:
The type 'System.Collections.ObjectModel.ObservableCollection`1<T0>' is defined in an assembly that is not referenced.
You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e,
Retargetable=Yes'. C:\ENM\Main\src\prod\Mobile\Stakeholder\UI.Android.vNext\Views\LocationsMapView.cs 40 32 UI.Android.vNext
The second error is:
foreach statement cannot operate on variables of type
'System.Collections.ObjectModel.ObservableCollection`1<BK.EMS.Stakeholder.Model.ViewModels.LocationViewModel>'
because 'System.Collections.ObjectModel.ObservableCollection`1<BK.EMS.Stakeholder.Model.ViewModels.LocationViewModel>'
does not contain a public definition for 'GetEnumerator'
C:\ENM\Main\src\prod\Mobile\Stakeholder\UI.Android.vNext\Views\LocationsMapView.cs 40 32 UI.Android.vNext
I have referenced the System.Windows assembly from the System.Windows.Droid project, which is supposed to forward ObservableCollection<>.
The lines where the error occurs:
private void AddLocationOverlays()
{
if (_itemizedOverlay.Size() > 0) _itemizedOverlay.ClearOverlayItems();
RunOnUiThread(() =>
{
foreach (var location in ViewModel.Locations)
{
_itemizedOverlay.AddOverlayItem(location);
}
_mapView.Invalidate();
});
}
The Locations property in my ViewModel looks like this:
public ObservableCollection<LocationViewModel> Locations
{
get { return _locations; }
set
{
_locations = value;
RaisePropertyChanged(() => Locations);
}
}
Nothing too complicated and works fine in the non-PCL models...
So how do I get around and fix this?
We now have a solution to this problem - see fix from Daniel Plaisted in Portable Class Library strong assembly reference problems in MonoTouch/MonoDroid
This fix is checked in at https://github.com/slodge/MvvmCross/commit/f6a88048467838e5ac5ca687744dc0b2d1958aa8
Update : See other answer. It appears we now have a solution to this problem!
I believe this is linked to this problem - Portable Class Library strong assembly reference problems in MonoTouch/MonoDroid
Which is linked to: https://github.com/slodge/MvvmCross/issues/41
This is raised with Xamarin as a bug: https://bugzilla.xamarin.com/show_bug.cgi?id=8035 and
I'm afraid I don't understand the recommended Strong Signing solutions right now.
Please upvote the bug report to alert the Microsoft PCL and Xamarin teams about this. The MS and Xamarin teams are talking to each other on this (albeit through me!), and I am hopeful we will find a way for either Microsoft or Xamarin to ship some signed DLLs.
In the meantime, some possible workarounds are:
Use IEnumerable access instead of ObservableCollection - the collection can still be an ObservableCollection instance, just don't reference it as an ObservableCollection in the UI code.
Try putting your iterating code in a class library rather than in an application project - bizarre as it feels, the compiler seems perfectly happy building the same code when its in a library rather than in an application
Try building in MonoDevelop with the Mono compiler - this doesn't seem to have the same strong name reference checks.
Looking at your sample code I would just try:
private ObservableCollection<LocationViewModel> _locations;
public IEnumerable<LocationViewModel> Locations
{
get { return _locations; }
set
{
if (value != null && !(value is ObservableCollection<LocationViewModel>)
{
throw new Exception("You must Set an ObservableCollection");
}
_locations = (ObservableCollection<LocationViewModel>)value;
RaisePropertyChanged(() => Locations);
}
}
then AddLocationOverlays could stay the same.
The only problem with this would be if you then wanted to bind to INotifyCollectionChanged on this collection - but I think you can find a way around this too if needed - e.g. you could somehow expose another INotifyCollectionChanged hook, or you could try using a hack involving an intermediary class library.
I accept that for now these are workarounds not solutions :/

Sporadic "an interface and cannot be constructed. Are you missing a type mapping"

Initial deployment of the site works fine. After about 2-3 hours, the controllers suddenly cannot be instantiated due to a dependency cannot be resolved (or at least that's what the error message tells me).
I have tried various things, but none of which seem to resolve it. Does anyone have any ideas what I can check?
Recently we had a similar situation with one of our Interceptors. All of a sudden it would no longer work. We intercept all calls to interfaces defined in assembly X.Y.Z.dll. But the OS decided to call the file X.Y.Z.DLL after a while. No new deployment happened in the meantime. But all of a sudden the name matching failed. Do you load some assemblies in your configuration by name? Maybe you should check for IgnoreCase in string comparisons.
Another idea: Do you use some kind of cache for your objects? Or a cache based LifetimeManager? If cache items get invalidated after some time you would loose those objects.
i still have no idea what was happening, but i managed to fix it. i was using a third-party bootstrapping library to register my components and mappings. but after rolling my own with MEF, and controlling the registrations myself, the issue went away. i'm guessing it was doing something funky by disposing things when it shouldn't have. thanks for the help.
In case someone encounters this problem using http://bootstrapper.codeplex.com/ with the following declaration:
Bootstrap.Bootstrapper
.With.Unity()
.And.AutoMapper()
.And.ServiceLocator()
.Start();
I replaced that with:
IUnityContainer container = new UnityContainer();
MEFContainer mefContainer = new MEFContainer();
mefContainer.UnityRegistry.ForEach(x => x.Register(container));
container.RegisterInstance<IMappingEngine>(Mapper.Engine);
mefContainer.AutoMapperRegistry.ForEach(x => x.CreateMap(Mapper.Configuration));
where
private class MEFContainer
{
[ImportMany(typeof(IUnityRegistration))]
public List<IUnityRegistration> UnityRegistry { get; set; }
[ImportMany(typeof(IMapCreator))]
public List<IMapCreator> AutoMapperRegistry { get; set; }
public MEFContainer()
{
var catalog = new DirectoryCatalog("bin");
var compositionContainer = new CompositionContainer(catalog);
compositionContainer.ComposeParts(this);
}
}
Note that IUnityRegistration.Register() and IMapCreator.CreateMap() are defined in the third-party code. MEF references System.ComponentModel.Composition
and System.ComponentModel.Composition.Hosting. Will eventually refactor.

Very Basic StructureMap?

Ok, I wrote this question up earlier today but I decided to delete it because I thought the question wasn't worded very well. I decided to wait until I had more time to compose it at home :).
I am just getting started with IOC/DI. I have done some research on which framework to use and decided to give StructureMap a spin. The following is the first tutorial I used:
http://dimecasts.net/Casts/CastDetails/39 by Derik Whittaker.
Anyways, I got everything working like a dream with EVERYTHING is hosted in the same project.
Here is my sample code:
[PluginFamily("SMTest",IsSingleton=true)]
public interface IVehicle
{
byte TopSpeed {set;get;}
byte MPG { set; get; }
}
[Pluggable("SMTest")]
public class Car : IVehicle
{
private byte mTopSpeed;
private byte mMPG;
#region IVehicle Members
byte IVehicle.TopSpeed
{
get
{
return mTopSpeed;
}
set
{
mTopSpeed = value;
}
}
public interface IConsumer
{
IVehicle Car { get; set; }
}
[Pluggable("SMTest")]
public class Consumer : StructureMapBasic.IConsumer
{
private IVehicle mCar;
public Consumer(IVehicle lcar)
{
Car = lcar;
}
public IVehicle Car { set; get; }
byte IVehicle.MPG
{
get
{
return mMPG;
}
set
{
mMPG = value;
}
}
#endregion
}
So anyways if i create the project above into a command line program and do the following:
var consumer = ObjectFactory.GetInstance<IConsumer>();
It works perfectly. No problems at all. When i create a seperate project in the solution and then change the project above to a DLL. I get the following error:
Test method StructureMapBasic.ConsumerTest.ConsumerConstructorTest
threw exception: StructureMap.StructureMapException: StructureMap
Exception Code: 202 No Default Instance defined for PluginFamily
StructureMapBasic.IConsumer, StructureMapBasic, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null.
At first i thought maybe the StructureMap.Config file didn't get into the new projects bin folder but that wasn't the case. It was there. Everythign compiles just fine this problem happens at runtime. I'm sure the solution is very easy but for the life of me i can't figure out whats going wrong. Any help would be MUCH appreciated.
Thanks,
Ncage
I took me all friggn day to figure this out. At first i thought i was just being an idiot and i was missing something stupid. Well i was not. I thought it was related to different projects but it was not. I created a new console application that consumed my StructureMapped DLL (If just coined a term ;) ). Anyways, after trying to spend all day on this problem i FINALLY found a post that described the problem. its a freakn bug in MSTest (my project i was having problems with was created in MSTest). Xunit here i come. Here is a post that describes the issue from the same guy who created the tutorial video:
http://devlicio.us/blogs/derik_whittaker/archive/2008/07/23/mstest-why-i-hate-you-you-cause-me-too-much-friction.aspx

Resources