WORKS! == Xamarin.Forms + .NET Standard + Entity Framework Core for SQLite on iOS, Android, UWP!

ChrisWReaChrisWRea CAMember ✭✭

Hi folks. Thought I'd share some tinkering I've done lately.

I wanted to see if I could get a Xamarin.Forms sample app adapted from using SQLite.Net PCL to using Entity Framework Core instead (but still SQLite underneath), on all three mobile platforms. I also wanted to use a .NET Standard project for shared app logic, instead of a PCL. And in particular, I wanted to make sure the combination could work on iOS not just in theory (simulator, no linking) but targeting a real device and using framework SDK linking — typically a picky build target combination, and EF Core did present some specific linking challenges.

I'm happy to say that all the key bits (frameworks, libraries, tools) do support this particular 3x cross-platform stack today — even if the tooling and project templates have a little catching up to do. (I found myself unloading projects in VS2017 a couple of times to make some manual adjustments to the *.csproj file.) Crossing my fingers that, soon, building an app on this stack won't require any special tricks and that project templates will facilitate.

FWIW, one of the reasons I'm interested in looking at EF Core over SQLite.NET PCL (which already worked across the 3x mobile platforms) is that EF Core enables further code reuse with a .NET server side of a non-trivial mobile app. Consider this potential round-trip scenario: (a) ASP.NET Core web API server app loads an object from SQL Server (or other store) using EF Core, (b) API server serializes object as JSON and sends over HTTP to mobile client app, (c) mobile app deserializes object from JSON, (d) mobile app uses EF Core to cache object locally in SQLite database, and (e) all the way back again on a change. While I don't believe in silver bullets, one less ORM in the mix will be nice.

Anyway, the result of my tinkering is shared at https://github.com/cwrea/XamarinTodo. Comments and questions welcome here.

Regards,

Chris W. Rea
@cwrea

«1

Posts

  • darrell.tunnelldarrell.tunnell USMember ✭✭
    edited June 2017

    Looks good to me - thank you. I am attempting to extend this further to bring Microsoft.Extensions.DependencyInjection into the mix, so that on startup we build a container, and register services into it similar to .net core - i.e

          services.AddDbContext<TodoItemDatabase>((options) =>
            {
                options.UseSqlite("TodoSQLite.db");
            });
    

    The App class can expose the IServiceProvider which can then be used to resolve dependencies.

    My goal is to get even closer to asp.net core code as possible :-)

  • DrewEDrewE USMember ✭✭

    Cool stuff Chris! I will definitely be playing with this over the next couple of days. I was looking for a SQL Lite implementation that supported .Net Standard x. I found one here - https://forums.xamarin.com/discussion/97780/sqlite-net-standard-pcl. Noting that this implementation is stripped of the ORM functionality, I started searching for other SQL Lite ORMs that support the standard. What you have done and the scenario that you have laid out is exactly why I was searching. I am using EF Core + MSSQL on the server, and would love to be able to reuse my models and repository services on the mobile side. An environmentally based wire-up of a single shared context implementation would be dreamy! Can't wait to take a look!

  • darrell.tunnelldarrell.tunnell USMember ✭✭

    I've extended this a bit on my fork, to add DI (similar to net core with IServiceProvider) as well as IHostingEnvironment and PhysicalFileProvider to work with files (similar to asp.net core web apps) here is my fork - https://github.com/dazinator/XamarinTodo/tree/morenetcore

  • sirmaksirmak TRBeta ✭✭
    edited July 2017

    use dapper for simplicity and performance, works well in both .net core/standard & xamarin with sqlite and others, forget entity framework.

  • ChrisWReaChrisWRea CAMember ✭✭
    edited July 2017

    @sirmak said:
    use dapper for simplicity and performance, works well in both .net core/standard & xamarin with sqlite and others, forget entity framework.

    Thank you for your comment. However, what you stated is not*completely accurate: Dapper will not work with Xamarin.iOS on an iOS device, as it uses classes in the System.Reflection.Emit namespace for IL code generation.

    Generating and executing IL code at runtime is not supported in Xamarin.iOS. See Xamarin Docs - iOS - Advanced Topics - Limitations. There is no JIT compiler in the runtime of a Xamarin.iOS application.

    You'll notice in Dapper's repository that there are many instances where Dapper generates IL code at runtime. There was an issue about the lack of support for Monotouch (Xamarin.iOS) and it wasn't closed as fixed. Rather it seems the Dapper team isn't [yet] actively interested in supporting Xamarin.iOS.

    It's important to be mindful of this Xamarin.iOS limitation: A given library may be supported across a variety of .NET platforms, including Xamarin.Android, by virtue of targeting .NET Standard or PCL profiles before that. However, Xamarin.iOS imposes additional limitations because it must use of ahead-of-time compilation to generate native code for deployment to iOS devices.

    The true acid test of whether a library runs on Xamarin.iOS is not whether it advertises .NET Standard or a compatible PCL profile, but whether key functionality actually works when targeting a real iOS device. In other words, having a multi-platform library work well on Xamarin.Android does not necessarily mean it will also work on Xamarin.iOS.

    So, while your remarks about Dapper's simplicity and performance are not inaccurate, Dapper is not an option for the multi-platform use case that I am specifically interested in, which includes iOS devices. Also, FWIW, Dapper's performance is excellent precisely because it uses IL code generation. Many .NET ORMs use IL code generation for the same reason, and that's why many of them also do not run on-device with Xamarin.iOS.

    Regards,

    Chris W. Rea
    @cwrea

  • ChrisWReaChrisWRea CAMember ✭✭

    Darrell and Drew, thank you also for your comments.

    @darrell.tunnell: My goal was specifically to adapt the Todo sample to EF Core, no more no less. However, thanks for your note about Microsoft.Extensions.DependencyInjection—there are certainly better practices that can be employed in a real application using EF Core. My goal, too, is to write data access code that can feel at home in an ASP.NET Core application on the server, as well as on mobile device clients.

    @DrewE: A while back I spent a lot of time searching for a solution to this problem. I actually spent some time trying to replace the IL-based dynamic method generation in PetaPoco with slower Reflection-based mapping that would work on iOS too, but I realized I was going down a rabbit hole I didn't want to go down. Once I'd learned about EF Core, I started monitoring its development, trying it out on iOS on a few occasions. It took a little longer than I'd hoped for pieces to click together, but I'm glad they did.

    Regards,

    Chris W. Rea
    @cwrea

  • sirmaksirmak TRBeta ✭✭
    edited July 2017

    @ChrisWRea thanks, that's right, I used dapper in xamarin/android, .net core and .net standard library but not in ios. Dapper cannot run on either ios probably nor on AOT enabled android because of reflection.emit used for materialization.

  • ArronSmithArronSmith GBMember

    @ChrisWRea - This all works really nicely (aside: thank you for figuring this out - I'd tried and failed), until I try to add a DateTimeOffset to my model at which point the world implodes with a System.ExecutionEngine exception:

    Attempting to JIT compile method '(wrapper runtime-invoke) <Module>:runtime_invoke_void__this___int_object_byte_byte_byte_byte_DateTimeOffset_byte (object,intptr,intptr,intptr)' while running in aot-only mode. See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/ for more information.

    I can think of several workarounds involving a modification of the model, but none of them especially appeal. Any thoughts?

  • ChrisWReaChrisWRea CAMember ✭✭

    @ArronSmith said:
    @ChrisWRea - This all works really nicely (aside: thank you for figuring this out - I'd tried and failed), until I try to add a DateTimeOffset to my model at which point the world implodes with a System.ExecutionEngine exception [...]

    (Aside: You're welcome.) So... how are you declaring your DateTimeOffset property and initializing your instance? Was your property a plain DateTimeOffset, or, say, a nullable value?

    FWIW, I was able to add a plain DateTimeOffset public property to TodoNETStd sample's TodoItem model, including initializing it in SaveItemAsync() with item.WillThisCrash = new DateTimeOffset(DateTime.Today);, and then subsequently displaying it on screen via binding to a string version of the same property. I didn't see a crash when running the iOS Release build on a real device. I tried this with Xamarin 4.5.0.486 and Xamarin.iOS 10.10.0.37.

    In any case, you're right there are workarounds for an issue like what you encountered, but nailing down the precise circumstances around the crash would be helpful for filing a bug report with Xamarin. While EF Core has been shown to work on iOS devices in general, I have no doubt that specific issues like what you've seen will crop up from time to time and need to be hammered out, whether in Xamarin bits or in EF Core itself.

    Regards,

    Chris W. Rea
    @cwrea

  • Hi Chris,

    Great project, I've pulled and ran it, and it's good to see it running. I have, however, run into some issues when I was trying to modify it to be a model similar to one in a different project of mine, namely one with an optional relationship between two models, represented with a Nullable field. With this extra field, it fails with an exception similar to one reported by ArronSmith when querying or inserting.

    Have you tried or got anything working with Nullables?

    Thanks,

    Will

  • ArronSmithArronSmith GBMember

    @ChrisWRea - I couldn't reproduce the DateTimeOffset bug in your sample project, or isolate it in mine so eventually I shoved in a legitimately urgghhhh but acceptable for what I'm doing workaround:

    [NotMapped]
    public DateTimeOffset registrationTime { get; set; }
    
     [JsonIgnore]
     public string registrationTimeString {
        get {
            return registrationTime.ToString();
        }
    
        set {
            registrationTime = DateTimeOffset.Parse(value);
        }
    }
    

    after which everything was rainbows and I moved on with my life, until today when I added a second instance of a custom enum to one of my models and observed the exception described above being thrown when running on devices, which led me to ponder whether I could reproduce the same behaviour in your sample by adding a second DateTimeOffset, which led to the below and a crash.

    public class TodoItem
    {
            // Changes here by @cwrea for adaptation to EF Core.
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int ID { get; set; }
            public string Name { get; set; }
            public string Notes { get; set; }
            public bool Done { get; set; }
    
    
            public DateTimeOffset ThisWillNotRuinChristmas { get; set; }
            public DateTimeOffset ButThisWill { get; set; }
    }
    
    

    This is possibly a bit closer to bug reportable - I'd be interested to know if you're able to reproduce it.

    (Also I'm still using Xamarin.iOS 10.10.0.37, since 10.12.x throws a NotImplemented exception on Linq queries - this feels very similar to the original problem but I lack the chops to meaningfully investigate.)

  • ArronSmithArronSmith GBMember

    Minor update:
    Everything appears to work as well as it ever did with Xamarin.iOS 11.0 - the NotImplementedException I mention above no longer rears its head. So that's good.

    On the DateTimeOffset front, doing this:

    public class TodoItem
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }
    
        [NotMapped]
        public string Name { get; set; }
        [NotMapped]
        public string Notes { get; set; }
        [NotMapped]
        public bool Done { get; set; }
    
        public DateTimeOffset ThisWillNotRuinChristmas { get; set; }
        public DateTimeOffset ButThisWill { get; set; }
    }
    

    Magically fixes everything, which makes me wonder if I'm in fact hitting https://github.com/aspnet/EntityFrameworkCore/issues/9249 .

  • AquirkyAquirky USMember

    Really great stuff. I've been banging my head against the wall trying to figure out the optimum combination of Xamarin Forms, SQLite, .NET Standard and Entity Framework and you have killed a bag of snakes in one stroke!

    But you are not there yet! Where are the tools? What good is Entity Framework without the tools?

    So I added Microsoft.EntityFrameworkCore.Tools nuget package. I added a property to TodoItem and tried to do an Add-Migration from the package manager console. Got this error...

    PM> Add-Migration MyMigration
    Could not load assembly 'TodoiOS'. Ensure it is referenced by the startup project 'Todo.UWP'.
    PM>

    Well of course TodoiOS is not referenced from Todo.UWP and never will be. Not sure why this error is occurring.

  • RafaelRomero.8190RafaelRomero.8190 USMember
    edited October 2017

    Hello I having the same problem as @ArronSmitht . But the problem is only happening on 32 bits devices.

    I dont know if the problem is caused for the numbers of fields in the model or because the model use nullable datetimeoffset.

    Is there a workaround to get entityframework working on 32 bits devices?

  • crawfordnetcrawfordnet Member ✭✭

    I've yet to be able to persist data to the emulator between debugging sessions.

    Each time I connect, it has to go through the process of creating my initial records. I've located the folder on my Mac where it is supposed to create the database file, but there's nothing in that folder.

    In the context class, I'm using 'Database.EnsureCreated();' , but even with the application running, I cannot see the file, which leads me to believe that Sqlite is actually using an in-memory connection.

    Any insight would be greatly appreciated!

    Thanks,

    Charlie

  • RyanRyan Member ✭✭

    Great Proj here... Im trying to setup this exact thing using NetStandard 2.0 and the latest but seems I am running into a bunch of issues with Android... have you experienced the same things?

  • trikktrikk USMember
    edited February 2018

    So I have an issue., I'm doing my own version but I think I replicated everything.
    When trying to create my own implementation of DBContext I get the following exception:
    "A suitable constructor for type 'Microsoft.EntityFrameworkCore.Internal.DiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+Infrastructure]' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."

    Im working on .NET Standard 2.0 so there might be some changes. Anyone know anything about it? There`s no dependencies needed and the issue arises when invoking the constructor (it never goes to protected Context(string path))

  • RyanRyan Member ✭✭

    Are you missing the DbContext constructor that has the signature MyContext(DbContextOptions options) : base(options)

  • LarryKenobiLarryKenobi USMember ✭✭

    I have the same problem as @trikk . Adding the constructor with DbContextOptions did not help. Looking at the example application he was able to get away without using DbContextOptions.

  • trikktrikk USMember
    edited February 2018

    I cant post the code but
    a) the sample project didnt have the constructor
    b) adding it didnt change a thing

  • LarryKenobiLarryKenobi USMember ✭✭

    I can post code.

    https://github.com/mattman624/Migrations

    This is my project, extremely simple. Followed this guide (https://blog.xamarin.com/building-android-apps-with-entity-framework/) after project setup. I get the same exact "Microsoft.EntityFrameworkCore.Internal.DiagnosticsLogger" error.

  • ChrisWReaChrisWRea CAMember ✭✭
    edited February 2018

    @trikk @LarryKenobi

    You're running into issues because of the linker. I noticed in @LarryKenobi's Migrations.Android project settings that under "Linker properties" (in the "Android Options" tab), the "Linking" option is set to "Sdk and User Assemblies" (and I'll assume by default).

    When linking is enabled, the linker removes from generated code any types and methods that the linker believes are not referenced. However, the linker isn't very smart. The linker does not know if a type or method will be referenced via reflection at runtime. If a method (say, a constructor) is referenced via reflection only, then without otherwise taking special precaution to preserve it, the linker would remove it, and at runtime you'd see an error when it is referenced.

    Back to the settings: Underneath the "Linking" option, notice "Skip linking assemblies". If you change that from empty to "Microsoft.EntityFrameworkCore;Microsoft.Extensions.Logging;Microsoft.Extensions.Options" (without quotes), you should be able to get past the exception about Microsoft.EntityFrameworkCore.Internal.DiagnosticsLogger not having a constructor. There may will be further similar issues that follow as query generation and the use of dependency injection both rely heavily on reflection. Update: I found a comment at this GitHub issue which describes a set of assemblies the linker should skip to (perhaps) get EF 2.0.1 working on Android. I haven't tried it yet myself.

    FWIW, in the iOS platform project of the XamarinTodo sample that I had adapted for EFCore v1, there is a LinkDescription.xml file which accomplishes much the same thing, but on a type level and not an assembly level.

    There's a longer explanation in this blog post by Miha Markic, which although it's about Autofac, does describe the essential issue at hand.

  • trikktrikk USMember

    After I went through the "skipping" part I finally manged to get "The entity type 'TodoItem' requires a primary key to be defined." even though I have it defined by the [Key] attribute which is probably connected with an issue already mentioned somewhere.

    Right now I`m severely dissapointed with all the workarounds that are necessary for a simple application to even work

  • LarryKenobiLarryKenobi USMember ✭✭

    Thanks for the help and direction @ChrisWRea .

    I followed the link and added those assemblies to the skip list. Now when I run I get the exception: >System.InvalidOperationException: A suitable constructor for type >'Microsoft.EntityFrameworkCore.Query.RelationalQueryContextFactory' could not be located. Ensure the type is concrete >and services are registered for all parameters of a public constructor.

    This looks like another linking problem, but the assembly is already added to the skip list! How can the constructor be missing if it wasn't linked away? MS wouldn't put out a class with no constructor...

    I agree with @trikk . This should be (relatively) easy, why is it so difficult to get this running? Extremely frustrating.

    Here is the skip list: Microsoft.EntityFrameworkCore;Microsoft.Extensions.Logging;Microsoft.Extensions.Options; Microsoft.EntityFrameworkCore; Microsoft.EntityFrameworkCore.Relational; Microsoft.EntityFrameworkCore.Sqlite;Remotion.Linq; Microsoft.Data.Sqlite.Core; Microsoft.EntityFrameworkCore.Sqlite.Core; Microsoft.Extensions.DependencyInjection.Abstractions;Microsoft.Extensions.DependencyInjection; Microsoft.Extensions.Logging.Abstractions; Microsoft.Extensions.Logging; Microsoft.Extensions.Caching.Abstractions; Microsoft.Extensions.Caching.Memory; Microsoft.Extensions.Options; Microsoft.Extensions.Primitives; System.Reflection; System.Reflection.Primitives; System.Linq; System.Linq.Expressions; System.Linq.Queryable;

  • ChrisWReaChrisWRea CAMember ✭✭
    edited February 2018

    @trikk @LarryKenobi

    FWIW, I absolutely agree that it is difficult to get running now, and is both disappointing and frustrating. Getting EF Core v1 working for iOS in the first place did take some special linking directives, but they were somewhat limited (for a sample, admittedly). Whereas, it looks like EF Core v2 has considerably more moving parts, and the kinds of dependencies in particular that are very sensitive in the presence of the linker. I was hoping things would get easier with EF Core as it evolved, not harder. Just getting a sample running on EF Core v2 looks like a major headache.

    IMHO, what is really needed is a way for an assembly itself to declare that it has definite dependencies on other types/methods, when references to those other types/methods may only be indirect/via reflection -- i.e. not something that can be statically determined by the linker. Such "self-contained" don't-skip directives could feed right into the linker, instead of us having to rediscover all the ugly details whenever we get a new version. Give us control over linking, but let the assemblies we depend on declare their own baseline requirements.

    Application developer consumers of a library like EF Core should not have to tell Xamarin about all of the umpteen types and methods that EF Core itself depends on but that are only used via reflection or other means of indirection. Discovering these is not trivial, and the exceptions are not incredibly informative as to the cause. Moreover, as an assembly evolves, even a supposedly "compatible" version update might break the build, because internal changes in the assembly's implementation could add indirect references not previously accounted for.

  • ValonKastrati.9619ValonKastrati.9619 USMember ✭✭
    edited February 2018

    hej after i added the skipping list i now get the following exception

    System.InvalidOperationException: A suitable constructor for type >'Microsoft.EntityFrameworkCore.Query.RelationalQueryContextFactory' could not be located. Ensure the type is concrete >and services are registered for all parameters of a public constructor.

    any idea how to fix this ?

    @ChrisWRea

  • Hello :)
    When I install any NuGet package "Microsoft.EntityFrameworkCore..." in any project, the application does not start. There is only a splashscreen. I just checked for android. Does anyone know why this is happening?

    Install "Microsoft.EntityFrameworkCore" => not work, only splashscreen, any error
    uninstall "Microsoft.EntityFrameworkCore" => it works again

    Xamarin.Forms + .Net Standard 2.0

  • Hero1v1Hero1v1 ZWMember

    same problem as @czubekone

  • ChrisWReaChrisWRea CAMember ✭✭

    Hi folks. I updated my original sample for .NET Standard 2.0. See https://github.com/cwrea/XamarinTodo/tree/NETStd20_EFCore115. More specifically, the following has changed:

    • The Xamarin Forms cross-platform project is now built as a .NET Standard 2.0 library, instead of 1.4.
    • The sample now references Entity Framework Core v1.1.5 instead of v1.1.2. (No, not v2 yet. See below.)
    • The sample now references Xamarin Forms v2.5 instead of v2.3.
    • The Android project now has linking enabled, with a LinkDescription.xml file showing how to tell the linker to not remove specific types and methods. This is essentially the same LinkDescription.xml from the iOS project. However, the Android project does allow a LinkDescription build action in the file properties window, so that's how LinkDescription.xml is effective in the Android project, while for iOS it remains necessary (on a PC, anyway) to reference LinkDescription.xml using additional arguments. I imagine a LinkDescription file can be better managed than a long list of assemblies in the project's "Skip linking assemblies" field.
    • The UWP project's minimum platform version is now 10.0.16299.0 (Fall Creator's Update), due to the change to use .NET Standard 2.0.
    • The iOS project adds iPad screen orientations, because I was testing using an iPad and found the lack annoying.

    NOTE: I did not update the sample to the latest Entity Framework Core v2. Getting this all working on EF Core v2 remains a challenge -- as evidenced by the comments above, and elsewhere. And yet, taking advantage of .NET Standard 2.0 doesn't imply that you must also move to EF Core v2 right now.

    Regards,

    Chris W. Rea
    @cwrea

  • ChrisWReaChrisWRea CAMember ✭✭

    tl;dr: I got the sample working on EF Core v2 for all three platforms, and with moderate linking enabled.

    After getting the sample updated to .NET Standard 2.0 (but not EF Core v2) yesterday, I started looking more closely at the issues specific to EF Core v2. I started by removing all EF Core v1 package references from all projects. Then, in the cross platform project, I added references to packages Microsoft.EntityFrameworkCore (2.0.1) and Microsoft.EntityFrameworkCore.Sqlite (2.0.1). Building succeeded; no code changes necessary.

    Next I turned to the UWP project. Getting it to build with EF Core v2 was as straightforward as with the cross platform project, and the running UWP app seems to work consistent with the EF Core v1 version.

    Next up was the iOS project. Building with EF Core v2 was also straightforward, but upon running, the app exited prematurely with complaints in the debug output window arising from database setup logic. Addressing the issue required one new line of code, placed in Main.cs: SQLitePCL.Batteries_V2.Init();. Refer to https://github.com/aspnet/EntityFramework.Docs/issues/597. After this workaround, the iOS app also seems to work consistent with the EF Core v1 version.

    On to Android. First, I checked previous assumptions about linking. I had a look at the newer cross-platform project templates in Visual Studio. My assumption made in the midst of earlier hastier troubleshooting (further above) was that the Android project "Linking" default was now "Sdk and User Assemblies". But that isn't so: In a Release build, the Android project in the cross-platform project template has linking set to "Sdk Assemblies Only", and consistent with the iOS project, where "Linker Behavior" was "Link Framework SDKs Only". And SDKs only is what I set for both iOS and Android in my earlier update to the sample.

    (Side note on an annoyance: Android projects have a "Linking" setting with options "None", "Sdk Assemblies Only", and "Sdk and User Assemblies", while iOS projects have a "Linker Behavior" setting, with options "Don't Link", "Link Framework SDKs Only", and "Link All". I suspect these may not strictly be differences in labeling. "Link All", to me, reads as potentially more aggressive than "Sdk and User Assemblies".)

    And yet, with linking in the Android project dialed back some, swapping out EF Core v1 for v2.0.1 wasn't all that was required. There remained a blocking issue. The app would build, but upon running would exit with a complaint in the debug output: monodroid-assembly "Could not load assembly 'System.Runtime.CompilerServices.Unsafe' during startup registration."

    I found that issue described at https://github.com/xamarin/xamarin-android/issues/1196 and with information about a workaround. And so I moved the Android project back to using a packages.config file for now, instead of using PackageReference elements that had been added to the .csproj file in the previous update to the sample.

    Essentially, I removed the reference to the cross platform project, plus all PackageReference elements from the Android csproj file. I added a packages.config file to the project, then used NuGet to add back the required Xamarin.Forms packages and dependencies, and EF Core v2 packages and dependencies. Along the way I also updated the Android target SDK to 8.0 as one of the Xamarin.Forms dependencies didn't agree with 7.0. Last, I added back the project reference to the cross-platform project.

    After moving to packages.config, I was finally able to build and successfully run the Android app with EF Core v2. Creating, updating, and deleting items all work consistent with the EF Core v1 version of the app. I tested on both a Kindle Fire HD 6 (Fire OS 5.6.0.1), as well as a Nexus 5 (Android 6.0.1). My Android 7.x phone is loaned out so I didn't try it on 7.x yet.

    See the updated sample at https://github.com/cwrea/XamarinTodo/tree/NETStd20_EFCore201

    Regards,

    Chris W. Rea
    @cwrea

  • BozhiQianBozhiQian AUUniversity ✭✭

    Hi @ChrisWRea, thanks for your update. I cloned your latest and tried to run it on VS2017 Emulator for android. I use Marshmallow (API 23, ver 6.0.0). When I start to run debug, I failed with following errors.

    1>Failure [INSTALL_FAILED_NO_MATCHING_ABIS]
    1>Done building project "Todo.Android.csproj".
    1>Build succeeded.
    1>Failure [INSTALL_FAILED_NO_MATCHING_ABIS]
    1>
    1>Deploy failed on 5" Marshmallow (6.0.0) XXHDPI Phone
    ========== Deploy: 0 succeeded, 1 failed, 0 skipped ==========
    

    Have you tried to run it on Android 6.0.0? Thanks.

  • ChrisWReaChrisWRea CAMember ✭✭
    edited February 2018

    Hi @BozhiQian. tl;dr You can do what you want to do. See the last paragraph below. But, FWIW, my goal here has been to try EF Core on actual devices. I've avoided emulators and simulators on purpose.

    For iOS, the only* test of whether a 3rd party library will work in an app built for iPhone or iPad is to test it on a real device (and, realistically, testing ought to go much deeper than the sample here does with EF Core.) There is no substitute. The iOS "Simulator" as it is called, runs an x86_64 version of iOS-- but no real iOS devices run on that architecture. Even if one were using the native Apple tools to build iOS apps (and I have done this), the limitations of the simulator quickly reveal themselves. [* If one wants to be pedantic, Apple must furthermore approve your app.]

    With Xamarin development, it gets worse: To facilitate developer productivity, Xamarin.iOS doesn't perform full AOT (ahead-of-time) compilation for apps when targeting the simulator. Refer to Xamarin docs > iOS > Under the Hood > iOS Architecture. For the simulator, Xamarin.iOS uses a version of the .NET CLR that JIT compiles intermediate code like any typical .NET environment. But no Xamarin.iOS apps will run that way on a real iOS device. Apps targeting a real device must go through an AOT compilation phase, and this reveals limitations not present if running with a .NET CLR.

    The practical impact of such limitations is quite real. Refer to iOS > Advanced Topics > Limitations for more information. For ORM-type logic, one should absolutely be concerned about these limitations and test on-device as early as possible. I tried many simple ORM libraries that claim wonderful performance in typical .NET settings, and are otherwise wonderful choices, but that simply won't run on iOS devices because they use features like Reflection.Emit to dynamically generate code at runtime (to avoid the performance penalty of reflection-based property mapping).

    And so when I do vetting of any 3rd party library, it is on a real device only. I'll use a simulator or emulator to increase development velocity once I've got confidence I'm not relying on code that would be forbidden from running on a real device, and re-check assumptions along the way.

    That being said, running the sample in an x86-based Android emulator is possible, after adjusting the Android project settings to include x86 as a supported architecture, as described at Stack Overflow here. Just bear in mind that an emulator's purpose is to speed up development, and not provide a guarantee that code will run on real devices.

  • BozhiQianBozhiQian AUUniversity ✭✭
    edited February 2018

    Appreciate @ChrisWRea for your detail explanation. I agree with you that using real device (both Android and iOS) for testing is critical. I tried to debug to my Huawei P9 (Android 7.0) but failed to connect it via Xamarin Live Player due to some configuration error.

    I did following your last suggestion to tick x86 in advanced settings so the previous error go away. And it works. The app is successfully deployed to 5" Marshmallow (6.0.0) XXHDPI Phone API Level23 (VS2017 emulator for Android).

    The key change you made is reference package from packages.config rather than packagereference in Android project so the 'System.Runtime.CompilerServices.Unsafe' would be deployed. It is great. You did amazing work!!!

    I also noticed that the 'LinkDescription.xml' in Android project is not needed and can be deleted.
    And .NET Standard reference is not needed as well in Android project.
    <!--<package id="NETStandard.Library" version="1.6.0" targetFramework="monoandroid80" />-->

    Let me try to follow your sample to do it myself. Thanks for your time.

  • markwtmarkwt Member ✭✭

    Hi @ChrisWRea , just came across this post. I've been working on exactly the same sort of setup for a new project of mine. I'm new to Xamarin and my 25+ years of software dev. experience are with mainly non MS products so this is quite a steep learning curve. My project is Xamarin Native (multi-fragment), MVVMCross, SQLite (multiple tables) for offline work with web service based synchronisation. What I'm currently confused about is when instances of EF DBContexts should be created? As I understand a DBContext is a "Unit of Work", in web app world I can see how a single context per request fits in but is this the same as an ViewModel in a xam app? There are very few examples and those that exist only show a context with a single DBSet<>. I did initially think about a DBContext created as a singleton (as I think I've read about benefits of a single connection on SQLite, which makes sense) but I believe this concept would be wrong. Also considered using repository pattern with EF but some have said EF already is repository pattern. Feel going round in circles at the moment so any thoughts from anyone would be appreciate, thanks

  • ChrisWReaChrisWRea CAMember ✭✭
    edited March 2018

    @markwt Using relatively short-lived DbContext instances throughout a mobile (or desktop) application would be preferred to a singleton. It's true that such apps don't have the same behaviour as web applications, where the lifetime of an HTTP request is a good scope, but there are other meaningful boundaries that can provide scope. Each view that is instantiated and lives for a limited amount of time to provide a specific feature in your app could be a candidate for scoping a DbContext instance somewhere underneath.

    Here are a few things to read on the subject. Some of these refer to older non-Core EF, and development platforms other than Xamarin, but I think the ideas carry over:

  • markwtmarkwt Member ✭✭

    Thanks @ChrisWRea for this. I've just implemented my own Unit of Work and Repository classes which use a DBContext. This will decouple the ORM from where I need data access (if I decide to scrap EF and use something else it should be reasonable straight-forward). Even though some say Repositories + EF is not necessary I can see some benefits particularly for large projects. Just playing around at the moment, thanks again

  • pprometeypprometey Member
    edited March 2018

    @Aquirky said:
    But you are not there yet! Where are the tools? What good is Entity Framework without the tools?

    Here it is written how to do it https_://docs.microsoft.com/en-us/ef/core/get-started/uwp/getting-started#install-entity-framework

    Edit the .csproj file and replace <TargetFramework>netstandard2.0</TargetFramework> with <TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks>

    it works

  • geedsengeedsen USMember ✭✭
    edited March 2018

    Hit the error 'Attempting to JIT compile method' as well. I have three DateTime fields in my model.

    iOS app, using a .NET standard library. And using EntityFramework for SQLite.
    The iOS app calls a routine to add an entity into a table:

    msg = new QTNC.NETStandard.Models.Message();
    msg.Received = DateTime.Now.ToUniversalTime();
    msg.Created = DateTime.Parse(messageReceived["Created"]);
    ...
    return msg;

    And message is defined as:

    public class Message
    {
    [Key]
    public Guid Id { get; set; }
    public string ProductName { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public DateTime Received { get; set; }
    public DateTime Read { get; set; }
    public DateTime Created { get; set; }
    public string HtmlBody { get; set; }
    public string TextColor { get; set; }
    public string BackgroundColor { get; set; }
    }

    The error happens on the database.Messages.Add(msg);
    Attempting to JIT compile method '(wrapper runtime-invoke) :runtime_invoke_void__this___Guid_object_object_DateTime_object_object_DateTime_DateTime_object_object (object,intptr,intptr,intptr)' while running in aot-only mode. See https://developer.xamarin.com/guides/ios/advanced_topics/limitations/ for more information.
    the Read property btw was nullable at first, and interestingly the error was almost the same but was referring to a DateTime then as well.

    And BTW, the link mentioned in the error (https://developer.xamarin.com/guides/ios/advanced_topics/limitations/) does not exist....

    The Android App calls the same method in the .NET Standard library, and has no problems. Moving the method to be part of the iOS app itself gives the same problem.
    I am using the 2.0.2 EntityFrameworkCore package.

    How to resolve this?

    Thanks

    Ben

  • geedsengeedsen USMember ✭✭

    Apparently Preview VS 15.7 should solve this, installing now.

  • cdelaunecdelaune Member

    @geedsen, I am having the same issue on iOS, both when attempting to work with tables that include nullable columns as well as tables that have a significant number of columns (currently 17 to be exact). I am eager to know if the 15.7 preview version does indeed fix this issue. Please report back!

    Thanks,
    Christian

Sign In or Register to comment.