I have a client/server solution using C#
, WPF
, ASP.NET WebAPI
and Entity Framework
. Client and server clases share the model among his projects. Now I am trying to create a new client, using Xamarin Forms and sharing the model to, but Entity Framework attributes(MaxLength
, Index
, NotMapped
, etc), are not compatible in a PCL. So this are the things that I've tried:
Import Microsoft.EntityFrameworkCore to the PCL Model
As described here, you should be able to use entity framework with Xamarin forms, so I convert the PCL to NetStandard 1.3, and it works, every EntityFramework attribute is allowed. But now the server project is not compatible with that standard and I cannot add packages like prism and Newtonsoft.Json in the model project.
Mock the attributes for Xamarin forms using the bait and switch trick
I've tried the approach described here, based on creating custom attributes in the model PCL, and redefining them in the class libraries. MyClient.Droid and MyClient.UWP redefine the attributes leaving them empty, and MyServer will redefine them with the Entity Framework functionality.
Custom IndexAttribute - Model PCL:
namespace Model.Compatibility
{
public class IndexAttribute : Attribute
{
public IndexAttribute()
{
}
}
}
Custom IndexAttribute - Server side:
[assembly: TypeForwardedToAttribute(typeof(Model.Compatibility.IndexAttribute))]
namespace Model.Compatibility
{
public class MockedIndexAttribute : System.ComponentModel.DataAnnotations.Schema.IndexAttribute
{
public MockedIndexAttribute()
{
}
}
}
I test this aproach calling var attribute = new Model.Compatibility.IndexAttribute();
. MockedIndexAttribute constructor is never called.
Create a Shared Project Instead of PCL
This way is a little more messy, but looks like it works. Just creating a new shared project for the model, and using conditional flags like this:
#if !__MOBILE__
[NotMapped, Index]
#endif
public Guid Id { get; set; }
I've not fully deployed this approach at the moment, but if I cannot make none of the first two ways working, I will go with this.
EDIT - Trying to make the "Bait and Switch Attributes" approach work
As @AdamPedley sugested and this thread to, I've redefined IndexAttribute in a new PCL(Xamarin.Compatibility), using the same namespace as the original one:
namespace System.ComponentModel.DataAnnotations.Schema
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class IndexAttribute : Attribute
{
public IndexAttribute() { }
}
}
Now, my PCL Model includes a reference to Xamarin.Compatibility, so I can use Index attribute in my model properties:
[Index]
public Guid Id { get; set; }
Then, from my Server project, I call the next line of code to check what constructor is called, the custom attribute, or the one defined by EntityFramework:
PropertyInfo prop = typeof(MyClass).GetProperty("Id");
object[] attributes = prop.GetCustomAttributes(true);
The constructor called is the custom one, so it does not work because it have to call to the attribute defined by EntityFramework. Thats is the thing that I don't know, what is the mechanism that make my model's PCL select custom attribute or EF attribute depending on the calling assembly.
I've also added a file in my server project, called TypeForwarding.Net.cs(as sugested here), that contains:
[assembly: TypeForwardedTo(typeof(IndexAttribute))]
But still not working.