I have a WCF service with this function :
namespace PortfolioSerivce
{
[ServiceContract]
public interface IService1
{
[OperationContract]
bool CreateOrders(List<OrderDTO> ListOrder);
}
}
and here its code
public bool CreateOrders(List<OrderDTO> ListOrder)
{
return true;
}
The class OrderDTO is defined as below :
[DataContract]
public class OrderDTO
{
[DataMember]
public int Id { get; set; }
[DataMember]
public char OrderType { get; set; }
[DataMember]
public float OrderedQty { get; set; }
[DataMember]
public float PreUNitCost { get; set; }
[DataMember]
public float PostUnitCost { get; set; }
[DataMember]
public float MarketPrice { get; set; }
[DataMember]
public float ClientId { get; set; }
[DataMember]
public float SecurityId { get; set; }
}
In WPF, I have a function in which I want to pass a list to the WCF function:
internal bool RemoteCreateOrders(List<Position> securityMarketDTO)
{
List<OrderDTO> ListOrders = new List<OrderDTO>();
Tools.MyRemoteService.CreateOrders((List<OrderDTO>)ListOrders);
return true;
}
When I compile I got those errors :
The best overloaded method match for 'PortfolioView.PortfolioService.Service1Client.CreateOrders(PortfolioView.PortfolioService.OrderDTO[])' has some invalid arguments
Cannot convert from 'System.Collections.Generic.List' to 'PortfolioView.PortfolioService.OrderDTO[]'
What is the problem here, as I send a list of OrderDTO from my app and in WCF I declared as parameter a list of OrderDTO. What conversion should I use?
Thanks in advance.
From you exception , you Service1Client's method CreateOrders needs a variable of type OrderDTO[], while you pass List.
Please pass the variable of right type , use ListOrders.ToArray to convert list to array.
Or if you want to pass List, please let vs generate List for collection when you add service reference.
When adding service reference using vs, you could click advanced at the bottom, and then your could configure Collection type.
Related
I have an AppService solution with the following Classes and i want to map from the SourceObject to the DestinationObject
Source Classes
public class SourceObject
{
public string Id { get; set; }
public string Name { get; set; }
public JsonApiSerializer.JsonApi.Relationship<SourceChildObject[]> childObjects { get; set; }
}
public class SourceChildObject
{
public string Id { get; set; }
public string type { get; set; }
}
Destination Classes
public class DestinationObject
{
public string Id { get; set; }
public string Name { get; set; }
public JsonApiSerializer.JsonApi.Relationship<DestinationChildObject[]> childObjects { get; set; }
}
public class DestinationChildObject
{
public string Id { get; set; }
public string type { get; set; }
}
Auto mapper is setup in the sartup class
services.AddAutoMapper(typeof(EntityMappingProfile));
And my mapping class loos like this
public class EntityMappingProfile : Profile
{
public EntityMappingProfile()
{
CreateMap<SourceObject, DestinationObject>();
CreateMap<Relationship<SourceChildObject[]>, Relationship<DestinationChildObject[]>>();
}
}
When i execute the solution all fields are mapped apart form the array field of type JsonApiSerializer.JsonApi.Relationship. The destination field is null. What am i doing wrong?
You forgot about creating a map between SourceChildObject and DestinationChildObject. Add this line to your EntityMappingProfile.
CreateMap<SourceChildObject, DestinationChildObject>();
And one more thing, when you are mapping generic types, you can enable mapping for all types with:
CreateMap(typeof(Relationship<>), typeof(Relationship<>));
instead of creating a map with concrete use case of a generic type.
I'm making a task management tool using AngularJS for the frontend and ASP.NET WEB API 2 for the backend. I have two entities in the database, a "Task" and a "Type". Each task has one type associated. The user fills a form when he can create a new task, and he has to select a type for that task.
Here's the C# code:
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
So my question is: how do I "connect" the two in the database? What I mean is, let's say I want to POST data to the database. I have to make two POSTs, right? One for the Task and one for the Type, since they're two separate entities.
But since they're stored with two different IDs, how do I know that a certain task has a certain type? In other words, if I send a GET request to KBTM_Task, how do I get the type of that task?
Modify your KBTM_Task entity to include the Type Id and foreign key relationship
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int TypeID { get; set; }
[ForeignKey("TypeID")]
public virtual KBTM_Type Type { get; set; }
}
This way when you get the data from the API your task object will already include the key ("TypeID") that can be updated and related object ("Type") that you can access its properties (Name, Description, ...).
When you update TypeID on the client object (model) you can simply push the updated task object to the API using $http.put() to handle the database update.
1) Add foreign key using fluent api (or data annotation)
// KBTM_Task.cs file
public class KBTM_Task
{
public int ID { get; set; }
public string TaskID { get; set; } // User defined ID
public string Title { get; set; }
public string Description { get; set; }
public int KBTM_TypeID {get;set}
public virtual KBTM_Type {get; set}
}
// KBTM_Type.cs file
public class KBTM_Type
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public KBTM_Task KBTM_Task { get; set;}
}
Add the following in the class inheriting from DbContext
public class KbtmContext : DbContext
{
...
//public virtual DbSet<KBTM_Task> KbtmTasks {get; set;}
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure KBTM_TypeID as FK for KBTM_Task
modelBuilder.Entity<KBTM_Task>()
.HasRequired(k => k.KBTM_Type)
.WithRequiredPrincipal(ad => ad.KBTM_Task);
}
}
2) If exposing the entity class in API response or request then you need to exclude navigation property from being serialized.
// KBTM_Task.cs file
public class KBTM_Task
{
...
[JsonIgnore]
public virtual KBTM_Type Type { get; set; }
}
To use the [JsonIgnore] atttribute use Install-Package Newtonsoft.Json in package manager console.(One of the popular solutions to manage serialization)
I have several ServiceStack ORMLite POCO, one is Company below.
public class Company
{
[AutoIncrement]
public int id { get; set; }
public string company { get; set; }
public int? companyNo { get; set; }
public bool? active { get; set; }
}
If two properties are valid in the following request: req.company="ABC Company", req.active=ture, and all other properties are null. Then it can return all records matching the two properties. The code may look like below:
public object Get(Company req)
{
return Db.Select<Company>().Where<Company>(req);
}
Does ServiceStack ORMLite have such a WHRER to auto-match the valid properties in the request DTO?
This is not a feature in OrmLite, but it's available in AutoQuery where you just need to define the Request DTO you want to query, e.g:
[Route("/company/search")]
public class QueryCompany : IQuery<Company>
{
public int Id { get; set; }
public string Company { get; set; }
public int? CompanyNo { get; set; }
public bool? Active { get; set; }
}
With just the Request DTO, ServiceStack automatically creates the Service for you which you can query like any other Service.
Enable AutoQuery
You can enable AutoQuery by registering the AutoQuery Feature, e.g:
Plugins.Add(new AutoQueryFeature { MaxLimit = 100 });
AutoQuery is available in the ServiceStack.Server NuGet package:
PM> Install-Package ServiceStack.Server
Thanks mythz. It works for me. My code is like below:
// ====== Model.cs ========
[Route("/company/search")]
public class QueryableCompany : QueryBase<Company>
{
public int? Id { get; set; }
public string Company { get; set; }
public int? CompanyNo { get; set; }
public bool? Active { get; set; }
}
public class Company
{
[AutoIncrement]
public int id { get; set; }
public string company { get; set; }
public int companyNo { get; set; }
public bool active { get; set; }
}
// ====== Service.cs ========
public IAutoQuery AutoQuery { get; set; }
public object Get(QueryableCompanies dto)
{
var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams());
var r = AutoQuery.Execute(dto, q);
return r.Results;
}
// ====== Global.asax.cs ========
public override void Configure(Container container)
{
//...
Plugins.Add(new AutoQueryFeature { MaxLimit = 100 });
//...
}
Then, I have two more questions based on the code above.
1) Since I have a lot of request DTOs, their code in Get(QueryableXXX dto) is all the same; How can I use a single generic Get() method to return all different types of DTO, like:
public object Get<T>(T dto) where T : IQuery
{
var q = AutoQuery.CreateQuery(dto, Request.GetRequestParams());
return AutoQuery.Execute(dto, q).Results;
}
2) In the Company example above, class QueryableCompany seems so similar to class Company, can AutoQuery provide some Attributes to class Company's members, and avoid to create another similar QueryableCompany?
When I build my model to be returned by WCF RIA Services to silverlight, the list properties are not shown in the silverlight client.
Class:
public class Batch
{
[DataMember]
public DateTime Time { get; set; }
[DataMember]
public List<BasicInfoModel> Accepted { get; set; }
[DataMember]
public List<BasicInfoModel> UnAccepted { get; set; }
}
public class Batch
{
[Key]
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
When in the client, it seems the Lists are not generated, for example, this is my loaded callback event:
private void Callback(LoadOperation<Batch> loadOperation)
{
//there is no such property as `Accepted`
var acceptedList = loadOperation.Entities.FirstOrDefault().Accepted;
}
Am I doing something wrong?
I suppose, you've missed DataContract attribute, e.g.
[DataContract]
public class Batch
{
[DataMember]
public DateTime Time { get; set; }
[DataMember]
public List<BasicInfoModel> Accepted { get; set; }
[DataMember]
public List<BasicInfoModel> UnAccepted { get; set; }
}
http://msdn.microsoft.com/en-us/library/ms733127.aspx
I query data with NHibernate in the server side, then I create a WCF service which is the one that publishes these NHibernate objects, they are correctly serialized to Silverlight, I modify them in my application but when I send them back to the server they get serlialized again, and Generic Lists get converted to Array so I cannot modify them anymore in the server side...
this is my class definition
public class BIMenu
{
public virtual Guid ID { get; set; }
public virtual String DisplayName { get; set; }
public virtual String ProgramToCall { get; set; }
public virtual IList<BIMenu> Children { get; set; }
public virtual IList<BISecurityProfile> SecurityProfiles { get; set; }
public virtual Boolean IsApplication
{
get
{
if (Children.Count < 1 && ProgramToCall != null)
return true;
return false;
}
}
public virtual Boolean IsFolder
{
get
{
return !IsApplication;
}
}
public BIMenu()
{
Children = new List<BIMenu>();
SecurityProfiles = new List<BISecurityProfile>();
}
}
and this is my contract
[ServiceContract]
public interface IBISecurityService
{
[OperationContract]
BIMenu GetMenu(String Name);
[OperationContract]
void SaveMenu(BIOnline.Model.BIMenu Menu);
[OperationContract]
void DeleteMenu(BIOnline.Model.BIMenu Menu);
}
Is your BIMenu class marked [DataContract]? I would expect it to be:
[DataContract]
public class BIMenu
{
[DataMember]
public virtual Guid ID { get; set; }
[DataMember]
public virtual String DisplayName { get; set; }
[DataMember]
public virtual String ProgramToCall { get; set; }
[DataMember]
public virtual IList<BIMenu> Children { get; set; }
[DataMember]
public virtual IList<BISecurityProfile> SecurityProfiles { get; set; }
Also, if your IList<BIMenu> Children and IList<BISecurityProfile> SecurityProfiles properties are being set to instances of the Array type, then that is perfectly valid, since Array implements IList. If you want to keep them as actual List<> instances, then just define the properties as List<> instead of IList<>, like this:
// Defined as actual Lists, not IList interfaces.
[DataMember]
public virtual List<BIMenu> Children { get; set; }
[DataMember]
public virtual List<BISecurityProfile> SecurityProfiles { get; set; }