Deserialization requires a parameterless constructor - uno-platform

I’ve an issue when using a .Net Standard 2.0 Nuget (same issue linking directly project) in WASM (#uno-platform):
Deserialization requires à parameterless constructor (Microsoft & Newtonsoft deserializator).
Obviously, the involved classes have parameterless constructors and the Nuget is working fine with UWP, WPF and Xamarin projects:
public class MCEFile
{
public List<Form> Forms { get; set; }
public List<Item> Items { get; set; }
[JsonConstructor]
public MCEFile()
{
Forms = new List<Form>();
Items = new List<Item>();
}
}
public class Item
{
public long ID { get; set; }
...
// - - - - - -
[JsonConstructor]
public Item()
{
// dummy for WASM
}
}
Any clue? Is there a solution or workaround? Or an issue I can follow?
Regards,
Michael

This is generally caused by a linker configuration issue.
If the class you are deserializing is located in an assembly or project that is not directly in the WebAssembly head project, you'll need to include the assembly name in the LinkerConfig.xml file.
For example:
<linker>
<assembly fullname="MyProject.Wasm" />
<assembly fullname="MyOtherLibrary" />
<assembly fullname="System.Core">
<!-- This is required by Json.NET and any expression.Compile caller -->
<type fullname="System.Linq.Expressions*" />
</assembly>
</linker>

Related

Xamarin Refit type initializer for System.Text.Json.JsonSerializer threw an exception

I am using Refit 6.1.15 in a Xamarin forms project. My code works exactly as expected on Android, but on iOS, I get a "The type initializer for 'System.Text.Json.JsonSerializer' threw an exception." when I execute my api.
I am using Microsoft.Extensions for DI - my configuration of my service in my Startup.cs class looks like this:
services.AddRefitClient<IAuthorizeApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri(BaseAddress))
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(15)
}));
My IAuthorizeAPI looks like this:
using System;
using System.Threading.Tasks;
using CivicMobile.Models;
namespace CivicMobile.Services
{
public interface IAuthorizeApi
{
[Post("/v1/DataStage/UserAuthentication/Authenticate?companyCode={queryParms.companyCode}&username={queryParms.username}&password={queryParms.password}&deviceIdentifier={queryParms.deviceIdentifier}")]
[QueryUriFormat(UriFormat.Unescaped)]
Task<ApiResponse<AuthResponse>> Login(Authorize queryParms);
}
My call that throws the error (in my ViewModel) is:
var authToken = await _authenticateService.Login(queryParms);
The return value for the Login (wrapped in ApiResponse) looks like this:
namespace CivicMobile.Models
{
public class AuthResponse
{
[AliasAs("access_token")]
public string AccessToken { get; set; }
[AliasAs("token_type")]
public string TokenType { get; set; }
[AliasAs("expires_in")]
public int ExpiresIn { get; set; }
[AliasAs("userName")]
public string Username { get; set; }
[AliasAs("userIdentifier")]
public string UserIdentifier { get; set; }
[AliasAs(".issued")]
public string IssuedAt { get; set; }
[AliasAs(".expires")]
public string ExpiresAt { get; set; }
}
I have replaced [AliasAs()] with [JsonPropertyName()] but the results are the same.
This error ONLY occurs on iOS - not on Android. Any suggestions?
Add the following code in your iOS(.csproj ):
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4">
<IncludeAssets>none</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.5.1">
< IncludeAssets>none</IncludeAssets>
</PackageReference>
</ItemGroup>
I took refit out of my DI Container and the problem went away entirely. No other changes in my code at all. I will try another DI system as I prefer to use DI in this app and refit.
Another update - I had AddHttpClient as well as the AddRefitClient in my ConfigureServices method. It was actually dead code (as I migrated to Refit but never got rid of dead code). That caused my POST to return a proper ApiResponse object with Content that was deserialized properly. So back to what I had planned in the beginning - thanks for your suggestion - it was helpful on another issue (a very large dataset returning - different Api).

'IdentityBuilder' does not contain a definition for 'AddEntityFrameworkStores' when upgrading to .NET 5

I'm trying to upgrade my .Net core 2.2 application to .net 5.0
This line no longer works:
services.AddIdentity<ApplicationUser, IdentityRole>
.AddEntityFrameworkStores<DataContext>()
.AddDefaultTokenProviders();
I get the message:
'IdentityBuilder' does not contain a definition for
'AddEntityFrameworkStores' and no accessible extension method
'AddEntityFrameworkStores' accepting a first argument of type
'IdentityBuilder' could be found
So based on my research I tried:
services.AddIdentity<ApplicationUser, IdentityRole>
.AddUserStore<DataContext>()
.AddDefaultTokenProviders();
However, while this compiles I get the following error at runtime:
Implementation type 'motorsport.Models.DataContext' can't be converted
to service type 'Microsoft.AspNetCore.Identity.IUserStore`
This is my DataContext:
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base(options)
{ }
public virtual DbSet<ApplicationUser> ApplicationUsers { get; set; }
public virtual DbSet<RefreshToken> RefreshTokens { get; set; }
}
What am I doing wrong? Note that my application is API only, I'm not using Razor Views at all.
You need to install Microsoft.AspNetCore.Identity.EntityFrameworkCore which provides types for persisting Identity data with Entity Framework Core.
Because AddEntityFrameworkStores has been moved into separate NuGet package Microsoft.AspNetCore.Identity.EntityFrameworkCore.

.NET Core 2.2 to 3.1 Azure functions project migration build fails

I have a .NET Core 2.2 Azure functions solution that I'm trying to migrate to .NET ore 3.1. I did the following steps:
I changed the project files target framework to netcoreapp3.1
I updated the Nuget packages to the latest stable version
I updated the global.json to
{
"sdk": {
"version": "3.1.100"
}
}
I have no PackageReference to "Microsoft.AspNetCore.App" in the project files
I installed the SDK from https://dotnet.microsoft.com/download/dotnet-core/3.1
I ran pm install -g azure-functions-core-tools#3
Everything went fine but at runtime, I had a serialization issue:
Newtonsoft.Json: Self-referencing loop detected with type 'Platform'. Path '[0].hierarchy.platform'."
I have the 2 DTOs:
public class Platform
{
[JsonRequired]
public string PlatformId { get; set; }
[JsonRequired]
public Guid HierarchyUuid { get; set; }
public Hierarchy Hierarchy { get; set; }
}
public class Hierarchy
{
[JsonRequired]
public string HierarchyId { get; set; }
[JsonIgnore]
public IEnumerable<Platform> Platform { get; set; }
}
I understand the reason of the issue but with .Net Core 2.2 as target framework this DTOs were successfully serialized. As mentioned by Microsoft, in the 3.1 version the serialization has been changed and I guess this is the cause of the issue. I replaced Newtonsoft.Json by System.Text.Json but still had the same issue. Finally, to prevent the circular references between Platform and Hierarchy I kept Newtonsoft.Json and added in the FunctionStartup.Configure method the following:
builder.Services.AddMvcCore().AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Which needs the Microsoft.AspNetCore.Mvc.NewtonsoftJson package.
When I installed the package version 3.1.1 I got a build error
Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'Microsoft.AspNetCore.Mvc.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
Does anybody have an idea why I have this error and how to resolve the issue?

Isolated RazorEngine failing to pass model to different AppDomain

When I render my template without the EditHistory member, this works. However, when I add that additional member that is within my application I get an exception Could not load file or assembly 'Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. Models is the project containing ContentModel, EditHistory and UserDetail.
public class ContentModel
{
public string Html { get; set; }
public string Title { get; set; }
public EditHistory History { get; set; }
}
public class EditHistory
{
public IReadOnlyCollection<UserDetail> Authors { get; set; }
}
public class UserDetail
{
public string Name { get; set; }
public string EmailAddress { get; set; }
}
I am wrapping ContentModel in a RazorDynamicObject as such:
Razor.Run("default.cshtml", typeof(ContentModel), RazorDynamicObject.Create(cm));
As mentioned above, it works without EditHistory being present, but fails when it is.
The sandbox is set up verbatim as per how it's done at https://antaris.github.io/RazorEngine/Isolation.html
How do I get it to work with complex custom types?
Running under ASP.NET.
Edit
I have created a minimal reproduction of the issue I'm facing. It's at https://github.com/knightmeister/RazorEngineIssue. If package restore fails, manually install-package razorengine.
First of all; I was never able to get your GitHub-code running. The following is based on my own reproducing code.
I think that you're getting Could not load file or assembly-exceptions because when you setup the sandbox AppDomain you're setting:
adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
This won't work in ASP.NET because assemblies are in the bin subfolder. To fix that, simply do this instead:
adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
+ "\\bin";
However, ASP.NET will by default shadow copy assemblies. Therefore just doing this change will probably cause another exception:
ArgumentException: Object type cannot be converted to target type.
That's because there's a mixup between assemblies loaded in the default app domain and the sandbox. The ones in the default app domain are located in a temporary shadow copy location and the ones in the sandbox are located in the bin-folder of your web application root.
The easiest way to fix this is to disable shadow copying by adding the following line under <system.web> in your Web.config:
<hostingEnvironment shadowCopyBinAssemblies="false"/>
In addition; I think it's better and easier to skip using RazorDynamicObject and instead mark your models with [Serializable]. In fact I never got RazorDynamicObject working properly.
The rest of this answer summarizes what I did to come to this conclusion
I think that this is due to a bug or limitation in RazorEngine. (I'm not so sure about this anymore, it might very well be that shadow copying and RazorDynamicObject cannot work together)
I've spent a couple of hours trying to figure out how to get this working but I've always ended up with a security exception being thrown from RazorEngine.
There is, however, a possible workaround: Ditch RazorDynamicObject and mark your model classes as serializable.
[Serializable]
public class ContentModel
{
public string Html { get; set; }
public string Title { get; set; }
public EditHistory History { get; set; }
}
[Serializable]
public class EditHistory
{
public IReadOnlyCollection<UserDetail> Authors { get; set; }
}
[Serializable]
public class UserDetail
{
public string Name { get; set; }
public string EmailAddress { get; set; }
}
And do:
Razor.Run("default.cshtml", typeof(ContentModel), cm); // no RazorDynamicObject
I couldn't get your repro code running, so I created my own based on your code:
Create a new Console application (Visual Studio)
In the package manager console, run: install-package razorengine
Copy code from your repro:
Line 25-38 and 43-65 from:
https://github.com/knightmeister/RazorEngineIssue/blob/master/Global.asax.cs
All models from: https://github.com/knightmeister/RazorEngineIssue/blob/master/Models/Models.cs
Mark models with [Serializable].
Remove RazorDynamicObject
To ensure that we really can render user details from the authors list, change the test template to:
string template = "#Model.History.Authors[0].EmailAddress";
Also, to make that template work, change Authors in EditHistory from IReadOnlyCollection<> to IReadOnlyList<>
I created a GIST with the resulting code:
https://gist.github.com/mwikstrom/983c8f61eb10ff1e915a
This works for me. It prints hello#world.com just as it should.
ASP.NET will shadow copy assemblies by default and that will cause additional problems with sandboxing.
To get this working under ASP.NET you'll have to do the following changes:
Disable ASP.NET shadow copying by adding the following under <system.web> in your Web.config file:
<hostingEnvironment shadowCopyBinAssemblies="false"/>
Append \bin to the sandbox's application base path. So in createRazorSandbox(...) do:
adSetup.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\bin";
I have tested this and it works just fine. My test project is simply:
An empty ASP.NET Web Application (created with Visual Studio), with install-package razorengine
<hostingEnvironment shadowCopyBinAssemblies="false"/> in Web.config.
The following Global.asax.cs:
https://gist.github.com/mwikstrom/ea2b90fd0d306ba3498c
There are other alternatives (besides disabling shadow copying) listed here:
https://github.com/Antaris/RazorEngine/issues/224
I mostly don't use complex types but a general rule is usually that only primitive datatypes are transferred ok (my own rule, since values often get lost for me otherwise). However, when looking at some old source code I noticed I did use many complex types, but I populated them in the Controller (e.g. in Public ActionResult Index()). After some reading I think it might work if you use something similar to this (untested, MSDN source, 2nd source):
[MetadataType(typeof(EditHistory))]
public partial class ContentModel
{
public string Html { get; set; }
public string Title { get; set; }
public EditHistory History { get; set; }
}
[MetadataType(typeof(UserDetail))]
public partial class EditHistory
{
public IReadOnlyCollection<UserDetail> Authors { get; set; }
}
public class UserDetail
{
public string Name { get; set; }
public string EmailAddress { get; set; }
}

Unable to Retrieve Metadata

MVC4 + Entity Framework 4.4 + MySql + POCO/Code First
I'm setting up the above configuration .. here are my classes:
namespace BTD.DataContext
{
public class BTDContext : DbContext
{
public BTDContext()
: base("name=BTDContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//modelBuilder.Conventions.Remove<System.Data.Entity.Infrastructure.IncludeMetadataConvention>();
}
public DbSet<Product> Products { get; set; }
public DbSet<ProductImage> ProductImages { get; set; }
}
}
namespace BTD.Data
{
[Table("Product")]
public class Product
{
[Key]
public long ProductId { get; set; }
[DisplayName("Manufacturer")]
public int? ManufacturerId { get; set; }
[Required]
[StringLength(150)]
public string Name { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Required]
[StringLength(120)]
public string URL { get; set; }
[Required]
[StringLength(75)]
[DisplayName("Meta Title")]
public string MetaTitle { get; set; }
[DataType(DataType.MultilineText)]
[DisplayName("Meta Description")]
public string MetaDescription { get; set; }
[Required]
[StringLength(25)]
public string Status { get; set; }
[DisplayName("Create Date/Time")]
public DateTime CreateDateTime { get; set; }
[DisplayName("Edit Date/Time")]
public DateTime EditDateTime { get; set; }
}
[Table("ProductImage")]
public class ProductImage
{
[Key]
public long ProductImageId { get; set; }
public long ProductId { get; set; }
public long? ProductVariantId { get; set; }
[Required]
public byte[] Image { get; set; }
public bool PrimaryImage { get; set; }
public DateTime CreateDateTime { get; set; }
public DateTime EditDateTime { get; set; }
}
}
Here is my web.config setup...
<connectionStrings>
<add name="BTDContext" connectionString="Server=localhost;Port=3306;Database=btd;User Id=root;Password=mypassword;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
The database AND tables already exist...
I'm still pretty new with mvc but was using this tutorial
The application builds fine... however when I try to add a controller using Product (BTD.Data) as my model class and BTDContext (BTD.DataContext) as my data context class I receive the following error:
Unable to retrieve metadata for BTD.Data.Product using the same
DbCompiledModel to create context against different types of database
servers is not supported. Instead, create a separate DbCompiledModel
for each type of server being used.
I am at a complete loss - I've scoured google with almost every different variation of that error message above I can think of but to no avail.
Here are the things i can verify...
MySql is working properly
I'm using MySql Connector version 6.5.4 and have created other ASP.net web forms + entity framework applications with ZERO problems
I have also tried including/removing this in my web.config:
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient"/>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
I've literally been working on this bug for days - I'm to the point now that I would be willing to pay someone to solve it.. no joke... I'd really love to use MVC 4 and Razor - I was so excited to get started on this, but now i'm pretty discouraged - I truly appreciate any help/guidance on this!
Also note - i'm using Entityframework from Nuget...
Another Note
I was using the default visual studio template that creates your MVC project with the account pages and other stuff. I JUST removed all references to the added files because they were trying to use the "DefaultConnection" which didn't exist - so i thought those files may be what was causing the error - however still no luck after removing them -
I just wanted to let everyone know i'm using the visual studio MVC project template which pre-creates a bunch of files. I will be trying to recreate this all from a blank MVC project which doesn't have those files - i will update this once i test that
UPDATE TO USING VS MVC Basic Template: Same error resulted - still no solution
ANOTHER PERSON EXPERIENCING THE SAME PROBLEM
Right here is another stackoverflow question that mimics mine - however I tried his solution to no avail - maybe someone else who is having this same problem can benefit from the link
UPDATE
I recently just tried putting this into MS Sql Server and the view scaffolding adds fine with no error - so I'm not sure if its my MySql database or connection string or what... driving me nuts..
Other References
It appears someone else is having the same issues I am - the only difference is they are using sql server - I tried tweaking all my code to follow the suggestions on this stackoverflow question/answer here but still to no avail
POSSIBLE FIX???
So this is weird... after hooking it up to MS Sql Server and adding the controller, then reverting the connection string to MySql it is actually WORKING with MySql... what the heck!??
So it seems that when you try to add your controller and the view scaffolding (is that the right phrase?) is added WITH the mysql connection string it fails...however if you hook it up to a sql server db, generate the scaffolding/controller, then revert to mysql connection string it works.... ?!?!
It seems that MVC4 Controller scaffolding is not properly recognizing MySql Connection String. Change the connection string as shown below when generating EF CRUD code for Controllers:
<connectionStrings>
<add name="BTDContext" connectionString="Data Source=host_name;Database=database_name;uid=user_id;pwd=password;" providerName="System.Data.SqlClient" />
</connectionStrings>
Change it back to standard when running the application:
<connectionStrings>
<add name="BTDContext" connectionString="Data Source=host_name;Database=database_name;uid=user_id;pwd=password;" providerName="MySql.Data.MySqlClient" />
</connectionStrings>
Note the change, provider name.
The imesh suggesting almost solve my problem, but additionally I temporary commented line
[DbConfigurationType(typeof(MySqlEFConfiguration))]
which was in DBContext class. And of course after creation controller this line should be uncommented and change back System.Data.SqlClient to MySql.Data.MySqlClient in config file.
Using VS 2013, MySQL Connector/NET 6.9.6, Entity Framework 6, Web API 2.2 and MySQL server 5.7 I had to combine the answers to prevent the error about "Unable to retrieve metadata".
To successfully add a controller to a .NET project that uses a MySQL connection, do the following:
Temporarily add a connection string with System.Data.SqlClient as the providerName, and comment the one for MySQL. It doesn't matter whether the connection string is valid.
Ensure that MySqlEFConfiguration isn't enabled in any way.
Rebuild.
About the second point, the MySQL documentation on using Connector/NET with EF6 states three possible ways to enable the MySqlEFConfiguration. Ensure that none of these are enabled while adding controllers using the VS template.
Adding the DbConfigurationTypeAttribute on the context class:
[DbConfigurationType(typeof(MySqlEFConfiguration))]
Calling DbConfiguration.SetConfiguration(new MySqlEFConfiguration())
at the application startup
Set the DbConfiguration type in the configuration file:
<entityFramework
codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration,
MySql.Data.Entity.EF6">
I tested also around this bug and saw an other problem.
Following code is in my Web.config (without, it don't work):
<entityFramework codeConfigurationType="MySql.Data.Entity.MySqlEFConfiguration, MySql.Data.Entity.EF6">
Changed it to:
<entityFramework>
Works for me... add the scaffolding and then change it back
I've been having the same problem using EF 4.3.1 and MySql Connecter/Net 6.6.4.0
This worked for me, no need to connect to a different db or extra code in the Context class.
Add this between the entityFramework tags in your web.config file when you want to build a scaffold:
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
Then comment the above code out when you want to run migrations and vice versa.
So you web.config will look like so:
<entityFramework>
<contexts>
<context type="ApptManager.Models.AppointmentsManagerContext, ApptManager">
<databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[ApptManager.Models.AppointmentsManagerContext, ApptManager], [ApptManager.Migrations.Configuration, ApptManager]], EntityFramework" />
</context>
</contexts>
<!--<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=.\SQLEXPRESS; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>-->
</entityFramework>
This is quite ridiculous how .NET developers have to jump through some arduous hoops in order to get their code working.
Working example
https://github.com/dublinan/mvc-mysql-ef-example
Links to my github project
Please try using the
System.ComponentModel.DataAnnotations
namespace along with the [Key] attribute on the EDM class members.
It worked for me.

Resources