I am using Glass Mapper : 4.0.1.8 to map multilist to the IEnumberablein Sitecore 8. It does returns the number of count in the IEnumberable correctly but the fields inside that are all mapped to null. Following is the code that I am using:
public void GetPromotedNews()
{
var NewsListingPage = Sitecore.Context.Database.GetItem(new ID(ItemIDS.NewsListingCorporate));
var NewsListingPageItem = NewsListingPage.GlassCast<NewsListingPage>();
foreach (var newslistingcategory in NewsListingPageItem.NewsCategory) //This is returning two results which are correct
{
var item = newslistingcategory.CategoryName; //this is always returning null ?
}
}
public class NewsListingPage
{
[SitecoreField(FieldName = "Page title")]
public string PageTitle { get; set; }
[SitecoreField(FieldName = "Page description")]
public string PageDescription {get; set;}
[SitecoreField(FieldName = "News category", Setting = SitecoreFieldSettings.InferType)]
public virtual IEnumerable<ContentCategory> NewsCategory { get; set; }
}
[SitecoreType(TemplateId = DCP.Resources.TemplateIDS.CategoryTemplateID, AutoMap = true)]
public class ContentCategory : SCItem
{
[SitecoreField(FieldName = "Category name")]
public string CategoryName { get; set; }
[SitecoreField(FieldName = "Category icon")]
public Image CategoryICON { get; set; }
[SitecoreField(FieldName = "text")]
public string Text { get; set; }
}
Try Updating your content category model to have virtual properties
[SitecoreType(TemplateId = DCP.Resources.TemplateIDS.CategoryTemplateID, AutoMap = true)]
public class ContentCategory : SCItem
{
[SitecoreField(FieldName = "Category name")]
public virtual string CategoryName { get; set; }
[SitecoreField(FieldName = "Category icon")]
public virtual Image CategoryICON { get; set; }
[SitecoreField(FieldName = "text")]
public virtual string Text { get; set; }
}
Making them virtual should do the trick.
An alternate reason you run into null using GlassMapper is it cannot resolve the type you are trying to map to. For example, if I set my type to string but it was really a List<string>. I would also recommend TDS. You can source control TDS items and auto generate your classes.
Two possible causes are when I ran into this issue.
Template is not published correctly.
I added following attribute on my field.
[SitecoreField(Setting = Glass.Mapper.Sc.Configuration.SitecoreFieldSettings.DontLoadLazily)]
Related
I have 2 classes
public class Product
{
public DateTime Date { get; set; }
public string Name { get; set; }
public int Amount { get; set; }
}
public class Campaign
{
public long CampaignId { get; set; }
public string CampaignName { get; set; }
public List<Product> Products { get; set; }
}
Code:
var campaign = new Campaign();
campaign.CampaignId = Item.CampaignId;
campaign.CampaignId = Item.CampaignId;
campaign.CampaignName = Item.CampaignName;
campaign.Products = productList;
campaignList.Add(campaign);
productList.Clear();
When I call productList.Clear(), my "campaign" deletes its campaign.Products.
How can I prevent that from happening?
campaign.Products = new List<Product>(productList);
because campaign.Products is the same reference of productList
they are both pointing to the same list , any action on one will be reflected in the other varialbe
you need to clone (make another copy of the list) by different ways as follwoing
campaign.Products = productList.GetClone();
or
campaign.Products = productList.ToList();
or
campaign.Products.AddRange(productList);
check the following url
https://www.techiedelight.com/clone-list-in-csharp/
I have problems with gerenating types, it returns error
500 - InvalidDataException
I can't understand whats wrong as my project builds fine and API works.
None of the types works except the metadata
https://testapi.bokamera.se/types/
Please help as i'm stuck
Regards Kristian
Here you can see my call using Postman
and here you can see my DTO causing the problem
namespace BokaMera.API.ServiceModel.Dtos
{
[Route("/customfields",
Verbs = "GET",
Summary = "Find custom fields",
Notes =
"Find custom fields defined for the bookings that the current admin user is authorized to view."
)]
[ApiResponse(HttpStatusCode.Unauthorized, "You were unauthorized to call this service")]
[ApiResponse(HttpStatusCode.Forbidden, "You have too low privilegies to call this service")]
public class CustomFieldQuery :
QueryBase<CustomFieldConfig, CustomFieldQueryResponse>
{
[ApiMember(
Description =
"One or multiple id's of custom fields to find",
ParameterType = "query",
IsRequired = false)]
public int[] Ids { get; set; }
[ApiMember(
Description =
"Company id to find custom fields for",
ParameterType = "query",
IsRequired = false)]
public Guid? CompanyId { get; set; }
[ApiMember(
Description =
"Table to which the custom field belongs to",
ParameterType = "query",
IsRequired = false)]
public string Table { get; set; }
[ApiMember(
Description =
"Active or removed fields, empty parameter includes both",
ParameterType = "query",
IsRequired = false)]
public bool? Active { get; set; }
}
public class CustomFieldQueryResponse
{
[ApiMember(Description = "Custom field id")]
public int Id { get; set; }
[ApiMember(Description = "Reference to company that owns the custom field configuration")]
public Guid CompanyId { get; set; }
[ApiMember(Description = "Group id")]
public int? GroupId { get; set; }
[ApiMember(Description = "Config id")]
public int ConfigId { get; set; }
[ApiMember(Description = "Configuration name. Example: \"Number of persons\".")]
public string ConfigName { get; set; }
[ApiMember(Description = "Field width. Example: 20")]
public int Width { get; set; }
[ApiMember(Description = "Column in database where to store the information. Example: \"TextField1\"")]
public string Column { get; set; }
[ApiMember(Description = "Custom field description. Example: \"For how many persons is this booking?\"")]
public string Description { get; set; }
[ApiMember(Description = "Data field of custom field. Valid values are: TextBox, ... Example: \"TextBox\"")]
public string DataType { get; set; }
[ApiMember(Description = "Default value of the field. Example: \"3\"")]
public string DefaultValue { get; set; }
[ApiMember(Description = "Determines if the field is required to have a value or not")]
public bool Required { get; set; }
[ApiMember(Description = "Error message shown to the user if the field data is required but not entered")]
public string MandatoryErrorMessage { get; set; }
[ApiMember(Description = "Max lenght of the field")]
public int MaxLength { get; set; }
[ApiMember(Description = "")]
public bool MultipleLineText { get; set; }
[ApiMember(Description = "Regular expression used for validation of the field")]
public string RegEx { get; set; }
[ApiMember(Description = "Error message shown if the regular expression validation failed")]
public string RegExErrorMessage { get; set; }
[ApiMember(Description = "If the custom field is active or have been removed")]
public bool Active { get; set; }
[ApiMember(Description = "Table to which the field belongs")]
public string Table { get; set; }
[ApiMember(Description = "")]
public List<CustomFieldLookupResponse> Values { get; set; }
}
[Alias("V_FreeFieldFieldLookUp")]
public class CustomFieldLookupResponse
{
[PrimaryKey]
[Alias("FieldLookupId")]
public int? Id { get; set; }
[Alias("FreeFieldId")]
public int CustomFieldId { get; set; }
[Alias("FieldlookupActive")]
public bool? Active { get; set; }
[Alias("FieldLookupGroupId")]
public int GroupId { get; set; }
[Alias("FieldlookupSortOrder")]
public int? SortOrder { get; set; }
[Alias("FieldlookupValue")]
public string Value { get; set; }
}
//Used when sending in values on a DTO request object to the services to save on the tables.
public class CustomFieldDataValue
{
public int Id { get; set; }
public string Column { get; set; }
public string Value { get; set; }
}
//Used to list all values on a DTO response object
public class CustomFieldData
{
public int Id { get; set; }
public string Column { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Value { get; set; }
}
//Used when post or put values for different DTOS, see example Resource Dtos
public class AddCustomField
{
public int Id { get; set; }
public string Value { get; set; }
}
}
And my service
namespace BokaMera.API.ServiceInterface.Services
{
public class CustomFieldService : AppServiceBase
{
public IAutoQueryDb AutoQuery { get; set; }
[Authenticate]
[RequiredRole(Role.ApplicationAdmin)]
public object Get(CustomFieldQuery request)
{
// Get the autoquery that we will append to
var q = AutoQuery.CreateQuery(request, Request.GetRequestParams());
// The user can only see his/her own time exceptions
q = q.Where(te => te.CompanyId == UserSession.CompanyId);
// Execute counts and return the query response
var response = AutoQuery.Execute(request, q);
return response;
}
}
}
If you were on v4.0.58, it had an issue with Add ServiceStack Reference which can be resolved by upgrading to any release after that.
The issue with your DTOs was because they contained illegal " character in the Metadata attributes, i.e:
[ApiMember(Description = "Configuration name. Example: \"Number of persons\".")]
public string ConfigName { get; set; }
We validate metadata attributes to prevent an attacker from potentially injecting illegal data that they could use to generate malicious in Service consumers.
So to prevent the error you can remove double quotes (") from strings in your metadata attributes, replacing them with single quotes (') is fine, otherwise you can disable token verification in your AppHost.Configure() with:
NativeTypesFeature.DisableTokenVerification = true;
Incidentally Exception details from Code Generation will be more visible in the next release from this commit, so it will be clearer to tell what the error was.
Deprecated Warnings
Please take note of the Deprecation messages (also covered in Breaking changes in each Release Notes). QueryBase has been renamed to QueryDb, e.g:
public class CustomFieldQuery :
QueryDb<CustomFieldConfig, CustomFieldQueryResponse>
Also it's better for your custom AutoQuery implementations to pass the entire IRequest instead of just the parameters, e.g:
var q = AutoQuery.CreateQuery(request, base.Request);
This has the same behavior except it also allows this AutoQuery Service to participate in Multitenancy requests.
I'm new to Entity/Linq/Lambda and I have the following problem:
I have a web application which provides a JSON Api through ASP.NET MVC. The database is MSSQL and I use the C# entity framework as data access layer.
When getting data from a single table, I need to convert this to an anonymous object, before I can convert it to JSON to avoid a circular reference error.
This is a simplified example, but take these tables for example:
If I simply want to return all the translators in JSON, this is how I go about it:
DBEntities db = new DBEntities();
var data = db.Translator.Select(x => new
{
TranslatorID = x.TranslatorID,
FirstName = x.FirstName,
LastName = x.LastName,
Email = x.Email,
Referenced = x.TranslatorLanguage.Count != 0
});
return Json(data, JsonRequestBehavior.AllowGet);
The generated Model classes by Entity would look something like this:
public partial class Translator
{
public Translator()
{
this.TranslatorLanguage = new HashSet<TranslatorLanguage>();
}
public int TranslatorID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public virtual ICollection<TranslatorLanguage> TranslatorLanguage { get; set; }
}
public partial class TranslatorLanguage
{
public int TranslatorLanguageID { get; set; }
public int SourceLanguageID { get; set; }
public int TargetLanguageID { get; set; }
public virtual Translator Translator { get; set; }
public virtual Language Language1 { get; set; }
public virtual Language Language2 { get; set; }
}
public partial class Language
{
public Language()
{
this.TranslatorLanguage = new HashSet<TranslatorLanguage>();
this.TranslatorLanguage1 = new HashSet<TranslatorLanguage>();
}
public int TranslatorLanguageID { get; set; }
public int SourceLanguageID { get; set; }
public int TargetLanguageID { get; set; }
public virtual ICollection<TranslatorLanguage> TranslatorLanguage { get; set; }
public virtual ICollection<TranslatorLanguage> TranslatorLanguage1 { get; set; }
}
But I would like to be able to return a JSON with all the translators where each Translator-object contains an array with the TranslatorLanguage entries, and for each source- and target language to have it's varchar code and description values.
I have no idea how to go about this,
Thanks in advance.
The same way you project (select) Translator to anonymous type, you can project TranslatorLanguage to a nested anonymous type list.
Since you have defined the necessary navigation properties, it's quite easy - all you need is to follow the navigation properties (i.e. navigate) inside the query like if they were objects:
var data = db.Translator.Select(t => new
{
TranslatorID = t.TranslatorID,
FirstName = t.FirstName,
LastName = t.LastName,
Email = t.Email,
Languages = t.TranslatorLanguage.Select(tl => new
{
SourceCode = tl.Language1.Code,
SourceDescription = tl.Language1.Description,
TargetCode = tl.Language2.Code,
TargetDescription = tl.Language2.Description,
}).ToList()
}).ToList();
In the EF query below, any time an child contact address field is assigned to the Address property of the TaxReceiptsWithChargesModel, I get the error message:
"Cannot create constant value of type 'AddressModel'"
If I comment out the line that assigns the address, then the error does not occur. What could the issue be?
Edit: Typically, the causes of this problem I've seen elsewhere have to do with using the contains or equals LINQ methods, but the cause of this particular issue seems to lie elsewhere.
Here are the relevant sections of code:
//GetChildContactAddress
var childContactAddress = lgcCcpModel.ChildContacts
.Where(cc => cc.UUID == ltrm.ChildContactId)
.Select(cc => new AddressModel()
{
Address1 = cc.Address.STREET,
City = cc.Address.CITY,
Province = cc.Address.PROVINCE,
PostalCode = cc.Address.POSTALCODE
}).FirstOrDefault();
//Create the Tax Receipt Model with the Charge List
return unitOfWork.LegacyTaxReceiptStore.GetQuery()
.Where(ltr => ltr.LegacyTaxReceiptId == ltrm.LegacyTaxReceiptId)
.Select(c => new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = ltrm.LegacyTaxReceiptId,
ChildContactId = ltrm.ChildContactId,
ChildContact = ltrm.ChildContact,
EmailAddress = ltrm.EmailAddress,
ChildId = ltrm.ChildId,
ChildName = ltrm.ChildName,
ChargesTotal = ltrm.ChargesTotal,
TaxReceiptAmount = ltrm.TaxReceiptAmount.Value,
TaxReceiptYear = ltrm.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{ltrm.TaxReceiptYear}-{ltrm.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
}).FirstOrDefault();
public class TaxReceiptsWithChargesModel : ITaxReceiptsModel
{
public int LegacyTaxReceiptId { get; set; }
public string ChildContactId { get; set; }
public string ChildContact { get; set; }
public string EmailAddress { get; set; }
public IAddressModel Address { get; set; }
public decimal? OpeningBalance { get; set; }
public decimal? InvoicesTotal { get; set; }
public decimal? PaymentsTotal { get; set; }
public string ChildId { get; set; }
public string ChildName { get; set; }
public decimal? ChargesTotal { get; set; }
public decimal? TaxReceiptAmount { get; set; }
public string State { get; set; }
public int TaxReceiptYear { get; set; }
public string ReceiptNumber { get; set; }
public int? BinaryDocumentId { get; set; }
public List<TaxReceiptsChargesModel> Charges { get; set; }
}
public interface IAddressModel
{
string Address1 { get; set; }
string Address2 { get; set; }
string City { get; set; }
string Country { get; set; }
string PostalCode { get; set; }
string Province { get; set; }
}
That is because childContactAddress object (and also taxReceiptChargesModelList) is already in memory and when you try to assign a complex object in the projection of your second query, the Linq provider can't translated that object to SQL. One option can be call AsEnumerable extension method:
return unitOfWork.LegacyTaxReceiptStore.GetQuery()
.Where(ltr => ltr.LegacyTaxReceiptId ==ltrm.LegacyTaxReceiptId)
.AsEnumerable()
.Select(c => new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = ltrm.LegacyTaxReceiptId,
ChildContactId = ltrm.ChildContactId,
ChildContact = ltrm.ChildContact,
EmailAddress = ltrm.EmailAddress,
ChildId = ltrm.ChildId,
ChildName = ltrm.ChildName,
ChargesTotal = ltrm.ChargesTotal,
TaxReceiptAmount = ltrm.TaxReceiptAmount.Value,
TaxReceiptYear = ltrm.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{ltrm.TaxReceiptYear}-{ltrm.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
}).FirstOrDefault();
Update
Your issue can be also solve this way:
var result=unitOfWork.LegacyTaxReceiptStore.GetQuery()
.FirstOrDefault(ltr => ltr.LegacyTaxReceiptId ==ltrm.LegacyTaxReceiptId);
return new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = result.LegacyTaxReceiptId,
ChildContactId = result.ChildContactId,
ChildContact = result.ChildContact,
EmailAddress = result.EmailAddress,
ChildId = result.ChildId,
ChildName = result.ChildName,
ChargesTotal = result.ChargesTotal,
TaxReceiptAmount = result.TaxReceiptAmount.Value,
TaxReceiptYear = result.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{result.TaxReceiptYear}-{result.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
};
You have to apply [Serializable()] decorator however you cannot do it to interfaces.
Instead, implement your custom interface with ISerializable {}
A similar question has been answered below, credit of this post goes to Oded.
Why are interfaces not [Serializable]?
Cheers
Can you please tell what is point of using interfaces as a model property.
Microsoft do not encourage use of in interfaces as a model property. You can restrict changes in your property by using getter and setter methods .
See this post
https://stackoverflow.com/a/8455558/2173098
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".