Blazored server localstorage only works with properties of an object, but not with fields? - server

I instantiated an object from the following class and shoved that into a Blazored server localstorage element.
public class StatusData{public string Message { get; set; } = string.Empty; }
When I changed the string property to a field, my Blazor app ran, but the app could not retrieve the localstorage object. I do not know if the object was put into localstorage, or if the retriever did not work.
public class StatusData { public string Message = string.Empty; }
I added the { get; set; } back in and the localstorage worked again.
I expected that using Message as a field or a property would have worked the same.
Can someone help me understand the difference?

This library uses System.Text.Json as its default Json library, and that has a default of ignoring fields.
You can configure it to include fields though.
In your startup/program file you need to configure the JsonSerializerOptions
builder.Services.AddBlazoredLocalStorage(config =>
config.JsonSerializerOptions.IncludeFields = true
);
README

Related

Do I need to duplicate my Entity Framework classes in Typescript when using Angular 2?

Let's say I have a nice C# backend with Entity Framework. I've got my database set up and a simple class like
public class MyItem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ItemID { get; set; }
public string ItemName { get; set; }
}
I've got a nice Angular2 front end where I retrieve data from an API and present such as...
template: '<div>{{ItemName}} - {{ItemID}}</div>'
At the moment I have a duplicate, seemingly redundant typescript class ie
export class MyItem{
ItemID: number;
ItemName: string;
}
Is there any way I can avoid this typescript class? Can I bind to an object that isn't defined in advance? In Angular 1 we could bind to any property on the scope
{{MyItem.SomeProperty}}
In my project I've used TypeLite.
It can generate TypeScript interfaces based on your C# classes. Worked just fine. If you change smth on you backend you'll see errors in your client code without running you app.
If you don't need type safety on the client side, you can use any as was said already.
E.g.
Next C# class:
public class Person {
public string Name { get; set; }
public List<address> Addresses { get; set; }
}
will be converted to
interface Person {
Name: string;
Addresses: Address[];
}
Also you can use next tools/extensions:
TypescriptSyntaxPaste
TypeWriter - one more powerfull extension for VS.
The TypeScript class/model isn't mandatory.
You can load your HTTP data into a variable and access it like any other object with properties and arrays. e.g. data.propertyname or data.arrayname[0].propertyname.
In Angular2 you can use the HTTP service and return data which can then be converted into a JSON object using data.json()
Here is an example:
import { Http } from '#angular/http';
...
constructor(private http: Http) {
{
this.http.get(url).subscribe(
data => {
var json = data.json();
console.log(json.propertyName);
}
);
}
you can certainly get data in an any object, However you will loose out on all the Type related feature supported by Typescript.

How to ignore properties marked with [IgnoreDataMember] when calling REST service

I am consuming a REST Xml service.
I have all the necessary classes to do this, (supplied by the dev who wrote the service) but at my end I have to save some of the responses to the DB to perform the tasks of the app I am writing.
So I have marked some of these classes I need to put in the DB as partial and extended them so that I can inherit from a DbEntity class which specifies an ID property so I can use EF to save them to the DB thus:
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
public class DbEntity : IDbEntity
{
[IgnoreDataMember]
[XmlIgnore]
public int ID { get; set; }
}
the problem I am facing now, is that when the service call is being de-serialized I get the error
Error in line 1 position 113. 'Element' 'ElementName' from namespace '' is not expected. Expecting element '_x003C_ID_x003E_k__BackingField'
I am simply making the call like this:
var response = await client.PostAsXmlAsync<TReq>("Some/API/Call", req);
TResp val = await msg.Content.ReadAsAsync<TResp>(response)
all the properties in the original classes have Orders specified with their DataMember attributes and I have clearly marked my DB properties to be Ignored, but to no avail.
is there any way I can get this to work? - ie getting the DataContractSerializer to actually ignore the properties I have marked to be ignored when de-serializing?
as an aside, these ignored properties are also being passed to the service when making a call - does IgnoreDataMember actually do anything?
seems that the way to do this is like this
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
[DataContract]
public class DbEntity : IDbEntity
{
[XmlIgnore]
public int ID { get; set; }
}
so basically adding the DataContract Attribute but omitting the DataMember attribute on the item you don't want
don't know how I missed that first time around. seems its opt in rather than opt out in this instance.

ServiceStack.Text.XmlSerializer.DeserializeFromString result change when I change the order of xmlnode. Why?

What is wrong with ServiceStack.Text.XmlSerializer ?
I have object:
public class weatherdata : IReturn<WashService>
{
public Location location { get; set; }
}
public class Location
{
public string name { get; set; }
public string country { get; set; }
}
Try to deserialize thirdparty xml like that:
var data = ServiceStack.Text.XmlSerializer.DeserializeFromString<weatherdata>("<weatherdata><location><name>Moscow</name><country>RU</country></location></weatherdata>");
data.location.name = Moscow.
data.location.country is NULL;
Change xml like that:
var data = ServiceStack.Text.XmlSerializer.DeserializeFromString<weatherdata>("<weatherdata><location><country>RU</country><name>Moscow</name></location></weatherdata>");
and see
data.location.name == "Moscow".
data.location.country =="RU";
Why so different results if I only change order?
As explained here, the default XML serializer used by ServiceStack (.NET's DataContract serializer) assumes that the XML elements must be in the same order as declared in your class. In XML schema terminology, the elements are declared as xs:sequence rather than xs:all. If you need to support XML elements in any possible ordering in the request, then you may need to override the XML serializer used by ServiceStack as explained in the link above.
If you just need to adjust the ordering of the XML elements, I believe you can specify an exact ordering for your elements by decorating your properties with DataMember attributes and specifying the Order property. If you do this, then you will also need to decorate your Location class with a DataContract attribute.

How to get EF POCOs from System.Data.Entities.DynamicProxies

My question is the same as this one
However, I don't really see a solution there. Lets say I have a simple model with two POCOs, Country and State.
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
public class State
{
public string Code { get; set; }
public string Name { get; set; }
public virtual Country Country { get; set; }
}
When I use the repository to .GetStateByCode(myCode), it retrieves a dynamic proxy object. I want to send that over the wire using a WCF service to my client. The dynamic proxy is not a know type so it fails.
Here are my alternatives. I can set ProxyCreationEnabled to false on the context and then my .GetStateByCode(myCode) gives me a POCO which is great. However, the navigation property in the POCO to Country is then NULL (not great).
Should I new up a state POCO and manually populate and return that from the dynamic proxy that is returned from the repository? Should I try to use AutoMapper to map the dynamic proxy objects to POCOs? Is there something I'm totally missing here?
I think the answer from Ladislav Mrnka is clear. The Warnings Still apply. Even with this idea below. Becareful what gets picked Up. He just didnt include , if you want to proceed how to easily get data from Object a to object B. That is question at hand really.
Sample solution
See nuget package ValueInjecter (not the only tool that can do this... but very easy to use)
it allows easy copying of One object to another especially with the same properties and types.
( remember the lazy loading / navigation implications).
So vanilla option is :
var PocoObject = new Poco();
PocoObject.InjectFrom(DynamicProxy); // copy contents of DynamicProxy to PocoObject
but check the default behaviour and consider a custom rule
var PocoObject = new Poco();
PocoObject.InjectFrom<CopyRule>(DynamicProxy);
public class CopyRule : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
bool usePropertry; // return if the property it be included in inject process
usePropertry = c.SourceProp.Name == "Id"; // just an example
//or
// usePropertry = c.SourceProp.Type... == "???"
return usePropertry;
}
}

Entity Framework error when submitting empty fields

VS 2010 Beta 2, .NET 4.
In my ASP.NET MVC 2 application, when I submit a form to an action method that accepts an object created by the entity framework, I get the following error:
Exception Details: System.Data.ConstraintException: This property cannot be set to a
null value.
Source Error:
Line 4500: OnTextChanging(value);
Line 4501: ReportPropertyChanging("Text");
Line 4502: _Text = StructuralObject.SetValidValue(value, false);
Line 4503: ReportPropertyChanged("Text");
Line 4504: OnTextChanged();
The property is called "Text" and is of type "text NOT NULL" in MS SQL 2008.
My action will check if the value is nullorempty, if it is, a model error will be added, but I get the error as soon as I submit the form.
Are you binding directly to the entity? Sure looks like it. So you have two choices:
Write a custom model binder which translates null -> empty string.
Bind to an edit model which allows nulls instead, and then change this to empty string when you copy the values to the entity in the action.
I'd choose #2, personally. I think you should always use view/edit models, and this is a great example of why.
I was having the same problem. I looked around and found a work around here. It describes the problem as being caused by the EF validation taking place before the Required field validation. It also shows how we can work around this problem by using a [DisplayFormat] Tag. Hope this will help you.
Here's the link to the question and the workaround:
Server-side validation of a REQUIRED String Property in MVC2 Entity Framework 4 does not work
Is this an issue with the MVC2 and Entity Framework 4 or is this by design? It appears that validation of EF properties works fine for datetime non-nullable (required) fields and data type validation of numeric versus string fields is working without having to use ViewModels.
I recreated the issue using with a simple FOOBAR table using a single, non-nullable varchar(50) column called barName in slq 2008. I generated the EF model from that database and quickly added a controller and a CREATE view for the FOOBAR entity. If I try to POST to the CREATE action without entering in a value for the property barName, VS steps into an exception within the designer.cs file of the model (just like the one above). When, I try to step past the exception, the validation message shows up on the form and the field is highlighted in pink.
It seems like something is not firing in the correct sequence. Because the exception occurs before VS steps into the HTTPPOST CREATE method.
I found the code from the ASP.Net MvcMusicStore sample helpful. http://mvcmusicstore.codeplex.com/releases/view/44445#DownloadId=119336
It appears that binding to the ViewModel fixes the issue.
namespace MvcMusicStore.ViewModels
{
public class StoreManagerViewModel
{
public Album Album { get; set; }
public List<Artist> Artists { get; set; }
public List<Genre> Genres { get; set; }
}
}
........
namespace MvcMusicStore.Models
{
[MetadataType(typeof(AlbumMetaData))]
public partial class Album
{
// Validation rules for the Album class
[Bind(Exclude = "AlbumId")]
public class AlbumMetaData
{
[ScaffoldColumn(false)]
public object AlbumId { get; set; }
[DisplayName("Genre")]
public object GenreId { get; set; }
[DisplayName("Artist")]
public object ArtistId { get; set; }
[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
public object Title { get; set; }
[DisplayName("Album Art URL")]
[StringLength(1024)]
public object AlbumArtUrl { get; set; }
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00, ErrorMessage="Price must be between 0.01 and 100.00")]
public object Price { get; set; }
}
}
}
Ashish Shakya's answer helped me. I added this attribute to the property and now it works.
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
So it looks like this:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Import the namespace:
using System.ComponentModel.DataAnnotations;
And add the attribute property [Required]
[Required]
public global::System.String MyProperty
{
get
{
return _MyProperty;
}
set
{
OnMyPropertyChanging(value);
ReportPropertyChanging("MyProperty");
_MyProperty = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("MyProperty");
OnMyPropertyChanged();
}
}
Thus ModelState.IsValid equals false, showing error message in the validation and will not fail on the server with Null.
I had the same problem and fixed it by making false to true like this:
Line 4502:
_Text = StructuralObject.SetValidValue(value, false);
I just had the same problem myself, and came here to find the solution. However, the answer can be enhanced.
Svavar's and HackITMngr were on the right track, however combining both gives the best outcome. You don't want to go decorating the generated classes, as you risk losing your custom changes upon modifications to the EF model.
[MetadataType(typeof(MyTableMetaData))]
public partial class MyTable
{
// Validation rules for the Album class
public class MyTableMetaData
{
[DisplayFormat(ConvertEmptyStringToNull = false, NullDisplayText="")]
public string MyTextProperty { get; set; }
}
}
To settle any arguments between the two. I'd say Svavar's was the direct answer, HackITMngr was the enhancement.
Works great for me!
I set StoreGeneratedPattern property as Computed for each field and it solved the problem for me.