Public C# Properties are invisible on Xamarin Forms Android - c#

My Xamarin Forms app is acting strangely when running on Android. When I run on UWP everything appears to work fine, but when I launch the same app on Android, the public properties of the model I'm binding seem to disappear, as if they don't exist.
The model is defined as an interface as shown here:
public interface IRegionModel
{
string Id { get; set; }
string Name { get; set; }
string ShortName { get; set; }
string UrlName { get; set; }
string Description { get; set; }
string CityId { get; set; }
}
the implementation is pretty much identical:
public class RegionModel : IRegionModel
{
public string Id { get; set; }
public string Name { get; set; }
public string ShortName { get; set; }
public string UrlName { get; set; }
public string Description { get; set; }
public string CityId { get; set; }
}
and I'm populating my ViewModel with an observable collection of the RegionModel type:
public class RegionListViewModel : ViewModelBase
{
public ObservableCollection<IRegionModel> Regions { get; set; } = new ObservableCollection<IRegionModel>();
protected string CityId { get; set; }
public void Init(string cityId)
{
CityId = cityId;
}
public async override void Start()
{
base.Start();
LoadDesignData();
IsLoading = false;
}
protected override void LoadDesignData()
{
base.LoadDesignData();
for (var i = 1; i < 5; i++)
{
var model = new RegionModel()
{
Id = i.ToString(),
Description = "Region description " + i.ToString(),
ShortName = "Downtown",
Name = "Downtown",
UrlName = "Downtown",
CityId = "mcallen"
};
Regions.Add(model);
}
}
}
as you can see, I have access to each of the properties of the model, and populate them with my properties.
however when I run the app on android, these properties are immediately invisible:
I don't get any exceptions or errors, but the properties are simply not there.
I thought perhaps it was due to stale binaries (as suggested here: C# some public properties are not accessible, actually completely missing)
However, I did a full clean and manual clean, clearing out all the bin/obj folders manually on every single project and rebuilt it. In addition I made some code changes and XAML changes and those are showing up, so the project definitely appears to be updating...
what else could possibly be wrong here? How can properties just disappear?

If you have linked your assemblies the analyzer may have failed to determine those properties are really used and it has stripped them.
Set the linkage options to "SDK Only" and it should work.

Related

Converting infinitely nested objects in .NET Core

EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?

entity framework c# eager loading inherited and nested properties

I have a following object as a model in project:
AbstractControll and AntivirusControll which inherits from AbstractControll.
public class AntivirusControll: AbstractControll
AnticvirusControll has property:
public List<Exclusion> Exclusions { get; set; }
And this part of code drives me creazy:
var a = _entities.AntivirusControlls.First(m => m.Id == 1);
var b = _entities.AbstractControlls.First(m => m.Id == 1);
In database AnticvirusControll has one exception,while in result of executing above code I get:
a.Exclusions - has one object ( which is great and ok )
b.Exclusions - has none!
How is it even called inheritance? It's not polymorphic, it's .... a bug I could tell. Lazy loading wont work in this case.
And while asking for AbstractControlls I Can't include any property from derivered class offcourse.
Any ideas how to fix it?
--EDIT
both classes;
public abstract class AbstractControll
{
public int Id { get; set; }
}
public abstract class AbstractControll
{
public int Id { get; set; }
}
public class AntivirusControll: AbstractControll
{
public class Exclusion
{
public int Id { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectType { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectName { get; set; }
[DataMember]
public ConfigurationItemDescription ExlusionCI { get; set; }
}
[Display(Name= "Is Antyvirus Enabled")]
[DataMember]
public bool? isAntyvirusEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isAntyvirusEnabledCI { get; set; }
[DataMember]
[Display(Name = "Is real time protection enabled")]
public bool? isRealTimeProtectionEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isRealTimeProtectionEnabledCI { get; set; }
[DataMember]
[Display(Name = "Virus definition not older than( in days)")]
[Required]
[Range(typeof(int),"1","365")]
public int? VirusDefinitionNotOlderThen { get; set; }
[DataMember]
public ConfigurationItemDescription VirusDefinitionNotOlderThenCI { get; set; }
[DataMember]
public List<Exclusion> Exclusions { get; set; }
public AntivirusControll()
{
isAntyvirusEnabled = true;
isRealTimeProtectionEnabled = true;
VirusDefinitionNotOlderThen = 7;
isAntyvirusEnabledCI = new ConfigurationItemDescription();
isRealTimeProtectionEnabledCI = new ConfigurationItemDescription();
VirusDefinitionNotOlderThenCI = new ConfigurationItemDescription();
Exclusions = new List<Exclusion>();
}
}
--Edit 2
Well... I wanto to clarify, what actualy I'm doing.
I have MVC + angular Application.
There is a document with some Controls( AbstractControll)
Each of them is specific Type for example: Antivirus, Encryption and so on. At this point I have about 20 of them, but I will have more probably. Most of those derived classes have inner classes like Exceptions in Antivirus.
Right.
Basicaly that's it. What is important- After getting "AbstractControll" I want to expose this object over webapi - so lazy loading is not applicable here( or maybe it could be?)
That's it. It runtime I don't know exat type of the controll, so I Can't Include Properties from for example "Antivirus", when operating on DbSet
What I have now is ugly if's block that returns propper object and includes everything, but i'm not happy about his "hack".

Entity Framework, eager loading entites

I have 3 classes which I would like to 'talk' to each other on a ASP.NET MVC C# WEBAPI app. They are, Item, which can have only one User but the User can make multiple Comments on multiple Items and a Comment can have multiple Users but only one Item
My classes are as follows:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Comment> Comments { get; set; }
public User User { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public ICollection<Item> Items { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Message { get; set; }
public bool Important { get; set; }
public Item Item { get; set; }
public User User { get; set; }
}
I'm using angularJs front end, and so that I don't get a forever repeating loop I have configured the following:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
I'm using entity framework 6 and I want to Display all items including the comments and the users who have commented
I have read and feel? that Projection using Linq is probably best?
I have the following in my dbContext. (P.S, I've disabled LazyLoading, and including the System.Data.Entity namespace)
using(var _db = new dbContext)
{
var model = _db.Items.Include(i=>i.Comments.Select(p=>p.User).Select(vm=>new ViewModelItem(){
//here I think is where I would say....
ViewModelItem.Name = x.Name,
ViewModelItem.Description = x.Description,
ViewModelItem.Comments = ///
ViewModelItem.Comments.User.Name = ///
})).ToList();
return Ok(model);
}
I'm not sure where to go from here.
So I want to display All the comments and include the User who owns the Item but also include All the comments for that Item, and all the Users who have commented on that Item.
Without causing an infinite loop.
If I'm not being clear, please ask me to clarify. Any help as always is greatly appreciated.
Thank you
Assuming your comments data is good this should do it.
var model = db.Comment.Select(p=>
new ViewModelItem {
Name = p.User.Name,
Comments=p,
Description=p.Item.Description,
});

Seed() not fully updating the database

I'm giving a go through some tutorials (here and here) on ASP.NET MVC, and decided to try a few things on my own. Now, I've got three tables, Resume, Descriptions, SubDescriptions. Here's the code for the three:
public class Resume
{
public Resume()
{
Descriptions = new List<Description>();
}
[Key]
public int ResumeId { get; set; }
[Required]
public string Employer { get; set; }
[DataType(DataType.Date)]
public DateTime StartDate { get; set; }
[DataType(DataType.Date)]
public DateTime EndDate { get; set; }
[Required]
public string Location { get; set; }
[Required]
public virtual ICollection<Description> Descriptions { get; set; }
}
public class Description
{
public Description()
{
SubDescriptions = new List<SubDescription>();
}
[Key]
public int DescriptionId { get; set; }
[ForeignKey("Resume")]
public int ResumeId { get; set; }
[Required]
public string Desc { get; set; }
public virtual Resume Resume { get; set; }
public virtual ICollection<SubDescription> SubDescriptions { get; set; }
}
public class SubDescription
{
[Key]
public int SubDescriptionId { get; set; }
[ForeignKey("Description")]
public int DescriptionId { get; set; }
[Required]
public string Sub { get; set; }
public virtual Description Description { get; set; }
}
And my Seed() is as follows:
protected override void Seed(ResumeDBContext context)
{
context.Resumes.AddOrUpdate(i => i.Employer,
new Resume
{
Employer = "Employer Test",
StartDate = DateTime.Parse("2012-3-26"),
EndDate = DateTime.Parse("2013-10-24"),
Location = "Houston, TX",
Descriptions = { new Description
{ Desc = "DescTest",
SubDescriptions = {new SubDescription {Sub = "SubTest"},
new SubDescription {Sub = "SubTest2"},
new SubDescription {Sub = "SubTest3"}}
},
new Description { Desc = "DescTest2" }}
}
);
}
Now, whenever I run update-database from my Package Manager Console, it says it's running Seed(). However, upon querying the database, my SubDescriptions table is still empty. Everything else populates as expected. I don't receive any errors, or anything of the sort. Am I missing something silly in my associations?
The Resume table is populated properly from the Seed(), and the Descriptions table is populated as well, with the appropriate association to the Resume table. Yet, following the same example to try to populate SubDescriptions, the table is just flat out empty. The associations and navigation properties appear to be set correctly, but as I'm new to this, I'm not 100% certain.
Okay, so I found the answer quite by accident. I dropped and recreated the database, and when it ran Seed() again, it populated all my tables as it should. Initially, I was making changes to the Seed() and updating, hoping that they'd be applied. But since the data already existed in the tables, it wasn't populating.

How should I handle lookups in my ViewModel?

My database table for buildings stores the building type as a code. In a separate lookup table the description for that code is stored.
How should I design my ViewModel and where will I need to make the call to get the associated description value?
I sort of can see one option. I want to know if there is a better option.
BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
Then in my view
code...
<p>#MyService.GetDescription(Model.BuildingTypeCode)</p>
...code
Am I incorrect in the way I am thinking? if I do the above I create a dependency in my View to the service?
Update 1
Working through some of the solutions offered. I seem to run into another issue. I can't access the constructor of each building directly...
public ViewResult Show(string ParcelId)
{
var result = _service.GetProperty(ParcelId);
var AltOwners = _service.GetAltOwners(ParcelId);
var Buildings = _service.GetBuildings(ParcelId);
ParcelDetailViewModel ViewModel = new ParcelDetailViewModel();
ViewModel.AltOwnership = new List<OwnerShipViewModel>();
ViewModel.Buildings = new List<BuildingViewModel>();
AutoMapper.Mapper.Map(result, ViewModel);
AutoMapper.Mapper.Map<IEnumerable<AltOwnership>, IEnumerable<OwnerShipViewModel>>(AltOwners,ViewModel.AltOwnership);
AutoMapper.Mapper.Map<IEnumerable<Building>, IEnumerable<BuildingViewModel>>(Buildings, ViewModel.Buildings);
ViewModel.Pool = _service.HasPool(ParcelId);
ViewModel.Homestead = _service.IsHomestead(ParcelId);
return View(ViewModel);
}
public class ParcelDetailViewModel
{
public IEnumerable<OwnerShipViewModel> AltOwnership { get; set; }
//public IEnumerable<ValueViewModel> Values { get; set; }
public IEnumerable<BuildingViewModel> Buildings { get; set; }
//public IEnumerable<TransferViewModel> Transfers { get; set; }
//public IEnumerable<SiteAddressViewModel> SiteAddresses { get; set; }
public string ParcelID { get; set; }
//public string ParcelDescription { get; set; }
//public int LandArea { get; set; }
//public string Incorporation { get; set; }
//public string SubdivisionCode {get;set;}
public string UseCode { get; set; }
//public string SecTwpRge { get; set; }
//public string Census { get; set; }
//public string Zoning { get; set; }
public Boolean Homestead {get;set;}
//public int TotalBuildingArea { get; set; }
//public int TotalLivingArea { get; set; }
//public int LivingUnits { get; set; }
//public int Beds { get; set; }
//public decimal Baths { get; set; }
public short Pool { get; set; }
//public int YearBuilt { get; set; }
}
My understanding is that the view model is meant for display ready data. I think the real problem here is putting model dependent logic into the view.
You can do your service lookup but keep that code in the controller. The view model should be considered display ready (save for some formatting).
class BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
and then do the lookup before you render:
public ActionResult Building()
{
var typeCode = // get from original source?
var model = new BuildingViewModel
{
BuildingTypeCode = MyService.GetDescription(typeCode)
};
return View("Building", model);
}
Having come from a long line of JSP custom tags I dread having any code hidden in the view layout. IMO, that layer should be as dumb as possible.
I would recommend having a helper that does that, or a DisplayTemplate
public class ViewHelpers
{
public static string GetDescription(string code)
{
MyService.GetDescription(Model.BuildingTypeCode);
}
}
or
#ModelType string
#Html.DisplayFor("",MyService.GetDescription(Model.BuildingTypeCode));
More info on templates: http://www.headcrash.us/blog/2011/09/custom-display-and-editor-templates-with-asp-net-mvc-3-razor/
Both of these approaches introduce a dependency on your service but you can test/change them in one single place, instead of the whole application (plus the usage looks cleaner).

Categories