Alternative to Using an Entity as a Parameter to an Invoke Method in WCF RIA Services - silverlight

Howdy, ya'll! First question on StackOverflow! :-)
So here's the scenario: We're working on a web app with Silverlight 4 and using WCF RIA Services 1.0 SP1 Beta for the web service. I have my entities in the Entity Framework Designer, but I'm using a slightly-modified ADO.NET C# POCO Entity Generator template to generate the classes.
What I'd like to do is have a method inside a Domain Service with the following signature:
[EnableClientAccess]
public class ResultService : DomainService
{
[Invoke]
public SerializableResult CalculateResult(EntityOne e1, EntityTwo e2);
}
I am returning both EntityOne and EntityTwo to the client through queries in other services, like so:
[EnableClientAccess]
public class EntityOneService : DomainService
{
public IQueryable<EntityOne> GetEntityOnes();
}
[EnableClientAccess]
public class EntityOneService : DomainService
{
public IQueryable<EntityTwo> GetEntityTwos();
}
Those classes are successfully being generated in the Silverlight project. The SerializableResult does not have a key.
When I try to compile, I get the following error: "Operation named 'CalculateResult' does not conform to the required signature. Parameter types must be an entity or complex type, a collection of complex types, or one of the predefined serializable types."
In my research, the most helpful information I found were in the comments of this post by Jeff Handley.
Of note, Peter asked in a comment:
I get an 'does not conform to the required signature ...' compile error if my complex object has an [Key] Attribute. When I remove this attribute I can use the object as parameter for an Invoke operation.
Jeff's response:
This is by design. Complex objects cannot have Key properties. If you have a Key the class gets treated as an Entity.
So it sounds as if any further efforts to try to get my method to work will be futile. However, I was wondering if anyone else has come across this problem, and what they did to solve it.
Thanks very much!

I have the following and it works for me.
namespace BusinessApplication2.Web
{
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
[EnableClientAccess()]
public class DomainService1 : DomainService
{
public IQueryable<EntityOne> GetEntityOnes()
{
return null;
}
public IQueryable<EntityTwo> GetEntityTwos()
{
return null;
}
[Invoke]
public SerializableResult GetSerializableResult(EntityOne one, EntityTwo two)
{
return new SerializableResult() { Result = "It woooooorrrked!" };
}
}
public class EntityOne
{
[Key]
public int Id { get; set; }
}
public class EntityTwo
{
[Key]
public int Id { get; set; }
}
public class SerializableResult
{
public string Result { get; set; }
}
}

Many thanks to Mr. Jeff Handley and Mr. Dinesh Kulkarni for the answer (through Twitter).
In order for an Entity to be used as a parameter in an invoke method, that Entity must be exposed through a query method existing within the same DomainService. The intention for this restriction is that
"Each domain service needs to be able to stand on its own."
By adding two dummy Query methods (see Jeff's answer for an example), I was able to compile my code.

Related

How to create a SQL Server table from a json.net model with Entity Framework

If I had a simple model
public class Company
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
How would I convert this model into a SQL Server table with Entity Framework code-first?
Answer to your question would actually end up being a full tutorial.
That said, I suggest that you visit the following website and get yourself familiar with Entity Framework Code First concepts:
http://www.entityframeworktutorial.net/code-first/entity-framework-code-first.aspx
Mentioned tutorial has both conceptual overview as well as code samples.
Once you are done with tutorial, you will understand the following code snippet:
public class ApplicationContext : DbContext
{
public DbSet<Company> Companies { get; set; }
}
Then you need to create adequate migration and apply it to your database which will end up with creation of "Companies" or "Company" table (depending on EF version you are using).

how to access made objects from the service

I have a WCF service and a WPF application in my solution.
The application contains objects I made (customer, products etc), my windows and my business logic.
I need to retrieve a list of customers using the service but the service doesn't know what is a customer.
I CAN put all of my objects in both projects or reference one project from the other but that doesn't seem like the right way.
Any idea what should I do here?
Use data contract in your service like.
[DataContract]
public class Customer
{
[DataMember]
public int CustomerID{ get; set; } }
[DataMember]
public string CustomerName{ get; set; }
}
public interface ICustomerService
{
[OperationContract]
List<Customer> GetAllCustomer();
}
public Class CustomerService:ICustomerService
{
List<Customer> GetAllCustomer()
{
// write your own code to fill List<Customer> ans return it
}
}
Thanks
Ck Nitin (TinTin)
When will add the service reference of WCF or add the .dll in which WCF service is define in case if you are calling the WCF service from code using ServiceHost class, you can create the object for this customer class and you can easily use it.
Thanks
Ck Nitin (TinTin)

Parameter must be an entity type exposed by the DomainService?

Trying to implement a domain service in a SL app and getting the following error:
Parameter 'spFolderCreate' of domain method 'CreateSharePointFolder' must be an entity type exposed by the DomainService.
[EnableClientAccess()]
public class FileUploadService : DomainService
{
public void CreateSharePointFolder(SharePointFolderCreate spFolderCreate)
{
SharePointFolder spf = new SharePointFolder();
spf.CreateFolder_ClientOM(spFolderCreate.listName, spFolderCreate.fileName);
}
[OperationContract]
void CreateSharePointFolder(SharePointFolderCreate spFolderCreate);
[DataContract]
public class SharePointFolderCreate
{
private string m_listName;
private string m_fileName;
[DataMember]
public string listName
{
get { return m_listName; }
set { m_listName = value; }
}
[DataMember]
public string fileName
{
get { return m_fileName; }
set { m_fileName = value; }
}
}
So am I missing something simple here to make this all work?
It may be that the framework is inferring the intended operation because you have the word "Create" prefixing the function name (CreateSharePointFolder). Details of this behaviour can be found here
Although that is all fine for DomainServices and EntityFramework, following the information in that article, it can be inferred that methods beginning "Delete" will be performing a delete of an entity, so must accept an entity as a parameter. The same is true for "Create" or "Insert" prefixed methods. Only "Get" or "Select" methods can take non-entity parameters, making it possible to pass a numeric id (for example) to a "Get" method.
Try changing your method name temporarily to "BlahSharePointFolder" to see if it is this convention of inferrance that's causing your problem.
Also, as there is no metadata defined for your SharePointFolderCreate DC, you might need to decorate the class (in addition to the [DataContract] attribute) with the [MetadataType] attribute. You will see how to implement this if you used the DomainServiceClass wizard and point to an EF model. There is a checkbox at the bottom for generating metadata. Somewhere in your solution.Web project you should find a domainservice.metadata.cs file. In this file, you will find examples of how to use the [MetadataType] attribute.
For the RIA WCF service to work correctly with your own methods, you need to ensure that all entities existing on the parameter list have at least one member with a [Key] attribute defined in their metadata class, and that the entity is returned somewhere on your DomainService in a "Get" method.
HTH
Lee

Send custom complex objects to Silverlight RIA services

I've created a complex object which itself include a list of another object.
Example:
public class MyClass1
{
private List<MyClass2> myClass2List
[Key]
public long Id { get; set; }
public string Name { get; set; }
[Include]
[Association("FK_MyClass1_MyClass2", "Id", "MyClass1Id")]
public List<MyClass2> MyClass2List
{
get
{
if (this.myClass2List == null)
{
this.myClass2List = new List<MyClass2>();
}
return this.myClass2List;
}
set { this.myClass2List = value; }
}
}
public class MyClass2
{
[Key]
public long Id { get; set; }
public string Value { get; set; }
public long MyClass1Id { get; set; }
}
Now I want to send an instance of MyClass1 (which its MyClass2List is full) to the RIA services.
My first try was creating a get method with MyClass1 return type (to expose MyClass1) and also creating an Insert method for MyClass1 and MyClass2. It works but the MyClass2 Insert method is useless! I insert all the information in MyClass1 method. Also the get method is useless!
This is the domain service that works:
[EnableClientAccess]
public class MyDomainService : DomainService
{
public MyClass1 GetMyClass1()
{
return null;
}
[Insert]
public void Insert(MyClass1 myClass1)
{
... (Main code)
}
[Insert]
public void Insert(MyClass2 myClass2)
{
// I leave this method empty because I do the job in MyClass1 Insert method.
// If I don't add this method the Add operation on MyClass2List will not work!
}
}
As you see it doesn't have a clear implementation. Although I could use the traditional WCF Silverlight-Enabled services and simply use a single method to insert the MyClass1 instance.
Note that I tried the [Invoke] method (A simple invoke method which gives the MyClass1 as an input parameter) but then "MyClass1.MyClass2List" is empty!!!
How can I send a complex object to RIA services without having such useless methods and dirty implementation? I need to do all my works just in a single method. I don't need tracking and etc here. Is it better to use the traditional WCF Services besides the RIA or is there another way about RIA?
Thanks in advance
You need to add [Composition] attribute to your one-to-many relationships as well. more info:[ +, +, + ]
Also Try to switch to "RIA Services EF Code First Support"
On the client you just call SubmitChanges on the domain context. RIA then calls the appropriate insert methods for you.

RIA Services SP2 Function Complex type not visible in Object Context

I am struggling with returning a complex type from my services layer. It doesnt seem to be accessible from my object context.
This is the query in the service layer. All compiling fine.
public IQueryable<USP_GetPostsByThreadID_Result> uspGetPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
When I try and call it from my client, the ForumContext is not seeing it. I checked the client generated file and nothing similar is being generated. Help!!!
The name of your method may not meet the expected convention for queries. Try one or both of the following:
Add the [Query] attribute
Rename the method to GetUspPostsByThreadID
Result:
[System.ServiceModel.DomainServices.Server.Query]
public IQueryable<USP_GetPostsByThreadID_Result> GetUspPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
Its very common to have a stored procedure returning data from multiple tables. The return type doesn't fit well under any of the Entity Types(Tables). Therefore if we define Complex Type as the return collection of objects from Stored Procedure invocation, it becomes quite a powerful tool for the developer.
Following these steps I have achieved successfully the configuration of complex type on a sample AdventureWorks database.
1. Refer the picture and ensure the Stored procedure and function import is done.
2. Add the Domain Service name it as AdventureDomainService.
3. Now its time to define the tell the RIA services framework to identify my Complex Type as Entity Type. To be able to do this, we need to identify a [Key] DataAnnotation. Entity types provide data structure to the application's data model and by design, each entity type is required to define a unique entity key. We can define key on one property or a set of properties in metadata class file AdventureDomainService.metadata.cs
First define the class then add MetadatatypeAttribute like :
[MetadataTypeAttribute(typeof(CTEmployeeManagers.CTEmployeeManagersMetadata))]
public partial class CTEmployeeManagers
{
internal sealed class CTEmployeeManagersMetadata
{
private CTEmployeeManagersMetadata() { }
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int ManagerID { get; set; }
public string ManagerFirstName { get; set; }
public string ManagerLastName { get; set; }
}
}
Define the Domain service method to return the collection of objects/entities for populating the Silverlight Grid or any other data consuming controls.
public IQueryable<CTEmployeeManagers> GetEmployeeManagers(int empId)
{
return this.ObjectContext.GetEmployeeManagers(empId).AsQueryable();
}
We define IQueryable if we are to fetch the records from datasources like SQL, whereas we define IEnumerable if we are to fetch the records from in memory collections,dictionaty,arrays.lists, etc.
Compile the server side to generate the client proxy.
In the Silverlight side open the MainPage.xaml or wherever the datagrid is put, then add following namespaces :
using System.ServiceModel.DomainServices.Client;
using SLBusinessApplication.Web;
using SLBusinessApplication.Web.Services;
..
Load the data and display:
public partial class MyPage : Page
{
AdventureDomainContext ctx = new AdventureDomainContext();
public MyPage()
{
InitializeComponent();
LoadOperation loadOp = this.ctx.Load(this.ctx.GetEmployeeManagersQuery(29));
myGrid.ItemsSource = loadOp.Entities;
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
That is all that is needed to do.
It has to be part of an entity. Complex types cannot be returned by themselves

Resources