Problems with servicestack and typelinks - c#

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.

Related

Entity Framework exception for parameters that have 'allow nulls' enabled

I am adding a new register into the SQL Server database using Entity Framework like this:
var configSlot = new DeviceConfig_DB
{
ID_DeviceConfig = 95,
ConfigName = configName,
ParamName = "Param1",
ParamValue = "1000",
ToolName = null,
ToolValue = null,
};
It returns a validation error exception because of ToolName and ToolValue fields, and only are accepted if I set a string value (that fields are nvarchar).
If I insert a new register using a SQL Server Management Studio query, it is accepted even if I don't provide those fields. They do have the 'allow nulls' option.
INSERT INTO [dbo].[DeviceConfig_DB] ([ID_DeviceConfig], [ConfigName], [ParamName], [ParamValue])
VALUES (96, 'test', 'Param1', '1000')
How can I insert a new register with Entity Framework with null values for those fields?
EDIT:
Here is the DeviceConfig_DB class
public partial class DeviceConfig_DB
{
public int ID_DeviceConfig { get; set; }
public Nullable<int> ID_PhysicalDevice { get; set; }
public string ConfigName { get; set; }
public string ParamName { get; set; }
public string ParamValue { get; set; }
public string ToolName { get; set; }
public string ToolValue { get; set; }
public virtual PhysicalDevice_DB PhysicalDevice_DB { get; set; }
}

Map two models with a matching property to a new model

I'll try to explain this the best that I can so it makes sense.
I have two Models - BuyerProfile and Producerprofile
BuyerProfile
public class BuyerProfile : IAuditTrack
{
[KeyProperty(Identity = true)]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int BuyerTypeId { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
public string Zipcode { get; set; }
public string Description { get; set; }
[NonStored]
public string BuyerTypeDisplay { get; set; }
}
ProducerProfile
public class ProducerProfile : IAuditTrack
{
[KeyProperty(Identity = true)]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
public string Zipcode { get; set; }
public string Description { get; set; }
}
I have a simple method on my controller that retrieves all of the profiles in the database and concatenates them together.
[HttpGet]
public JsonResult GetAllProfiles()
{
var buyerProfiles = _profileService.GetAllBuyerProfiles();
var producerProfiles = _profileService.GetAllProducerProfiles();
var profiles = buyerProfiles.Concat(producerProfiles);
return Json(profiles, JsonRequestBehavior.AllowGet);
}
Now what I would like to do is be able to find every BuyerProfile and ProducerProfile that share the same UserId and merge them together into a new model that would look like this:
public class BuyerProducerprofile
{
public string UserId { get; set; }
public string BuyerName { get; set; }
public string ProducerName { get; set; }
}
The current system that I'm building only allows users to complete 1 BuyerProfile and 1 ProducerProfile.
So for example, in the result set I might have a BuyerProfile that contains the following information:
Id -> 1543
UserId -> abc123
Name -> Bob's Buying Company
and a ProducerProfile that contains the following information:
Id -> 1678
UserId -> abc123
Name -> Bob's Produce Company
I would like to be able to combine the two into my new model so that it looks something like this:
UserId -> abc123
BuyerName -> Bob's Buying Company
ProducerName -> Bob's Produce Company
I'm not sure if this is at all possible without using some kind of Nuget package but it would be awesome if I didn't have to use one that I don't already have.
I also am currently using AutoMapper to do some of my mapping but I couldn't find any documentation that shows being able to use it to do this.
what you want to do is called a join. you can do it like this
var buyerProfiles = _profileService.GetAllBuyerProfiles();
var producerProfiles = _profileService.GetAllProducerProfiles();
var combinedProfiles =
from bp in buyerProfiles
join pp in producerProfiles on bp.UserId equals pp.UserId
select new BuyerProducerprofile()
{
UserId = pp.UserId,
BuyerName = bp.Name,
ProducerName = pp.Name
}
note: if the same user can have more than one of a type of profile, this will return a result for every combination of buyer profile and producer profile that can be made for that user.
other note: this is what is called an "inner join", and it will only give you results for users that have both profiles. You can do other kinds of joins too, but syntax for those joins doesn't feel very natural, and I don't have them committed to memory. I'm sure a google search can find the syntax for you.

Mapping MultiList using Glass Mapper

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)]

How to know if RESTful request didn't contain some arguments in ASP.Net Web API 2?

I want my client to be able to sent some data of the model to the web via Restful request.
How can I know if not all part of the object is sent?
For example, the request sent only id, datetime_updated but not qty and datetime_updated.
I know that the framework will set the value to the default of its type, so I can check if DateTime wasn't sent (the default value is 1/1/0001 12:00:00AM which have no meaning in my application). But what about int, I can't simply check that if the value is 0 (0 has it meaning).
// Model
namespace TestingAPI.Models
{
public class Operator
{
public int pkey { get; set; }
public string id { get; set; }
public int qty {get; set;}
public DateTime datetime_created { get; set; }
public DateTime datetime_updated { get; set; }
}
}
// Controller
namespace TestingApi.Controllers
{
public class ProcessingPalletController : ApiController
{
public Dictionary<string, object> post(Product dataIn)
{
// how can I know if not all argument in Product is sent?
}
}
}
You can use attribute over your member of model and check Weather you model is valid or not.
Like if you want to make any property require you can use [Required] attribute over you model field.
public class Operator
{
[Required]
public int pkey { get; set; }
public string id { get; set; }
public int qty {get; set;}
public DateTime datetime_created { get; set; }
public DateTime datetime_updated { get; set; }
}
and inside your
public Dictionary<string, object> post(Product dataIn)
{
if (ModelState.IsValid)
{
}
check model is valid or not as above. You can get the error count etc for each model field (property).
You can also create your own attribute and use them. Few examples of custom attribute
http://www.codeproject.com/Articles/301022/Creating-Custom-Validation-Attribute-in-MVC
You can make the optional members nullable:
namespace TestingAPI.Models
{
public class Operator
{
public int pkey { get; set; }
public string id { get; set; }
public int? qty {get; set;}
public DateTime datetime_created { get; set; }
public DateTime? datetime_updated { get; set; }
}
}
When the consumer doesn't provide them, the properties will be null.

Windows Azure Mobile Service: InsertAsync

I followed the Windows Azure mobile service guide given by Microsoft over here.
I create a category class which represented the category table as follows:
public class category
{
public int Id { get; set; }
//// TODO: Add the following serialization attribute.
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
//// TODO: Add the following serialization attribute.
[JsonProperty(PropertyName = "subscribers")] //Number of Subscribers
public int Subscribers { get; set; }
[JsonProperty(PropertyName = "posts")] //Number of posts inside this category
public int Posts { get; set; }
}
I then inserted an entry into the database as give:
private IMobileServiceTable<category> categoryTable = App.MobileService.GetTable<category>();
category temp = new category() { Name = "test", Posts = 1, Subscribers = 2 };
await categoryTable.InsertAsync(temp);
All worked fine till here. Then i created a users class to represent the users table as follows:
class users
{
public int Id { get; set; } //the generated ID by the mobile service.
//// TODO: Add the following serialization attribute.
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
//// TODO: Add the following serialization attribute.
[JsonProperty(PropertyName = "nusnet")]
public string NUSNET { get; set; }
[JsonProperty(PropertyName = "email")]
public string Email { get; set; }
[JsonProperty(PropertyName = "faculty")]
public string Faculty { get; set; }
}
Now when I try to add in a user:
await userTable.InsertAsync(loggedInUser);
where logged in user is the details of the user. As given in the guide, i leave the Id filed empty and during debugging I notice that the Id is set as 0.
I get an error:
NewtonSoft.JSON.JsonSerializationException: {"Error getting value from 'Id' on 'NUSocial.users'."}
I have been trying fixing this for a while now but I have no clue on what is going wrong.
I think you'll need to apply the JSON attribute to the Id property. This is a sample of what my code, doing the same thing, looks like:
[DataContract]
public class Scores
{
[JsonProperty(PropertyName = "id")]
[DataMember]
public int Id { get; set; }
[JsonProperty(PropertyName = "UserName")]
[DataMember]
public string UserName { get; set; }
...
await scoresTable.InsertAsync(new Scores
{
UserName = _userName,
Score = (int) Score
});

Categories