I have created many class as my data class i.e:
[DataContract]
public class pCity
{
[DataMember]
public string code { get; set; }
[DataMember]
public string cityName { get; set; }
[DataMember]
public string provinceCode { get; set; }
}
I know if I put them into the WCF's svc.cs file or use them in WCF then it will be added and Silverlight side will see them from the Wcf Service Client's reference.
But I don't want my wcf file getting to large, so I store them into difference classes and in another class library project, reference it in Silverlight's Web Project.
Is there a quick way I can add them all into WCF (without doing the things I described above) so I can see them in Wcf Service Client's reference.
Thanks in advance.
King
They will never show up in a client's reference unless they are actually used by the service. That is, they must be either the type of a parameter, or else be the return type from an operation.
Related
I'm developing a windows service that reads information from the app.config at start-up which should allow us to change internal thread configuration without redeploying the service.
I created some custom configuration sections and elements as follows (implementation omitted):
public class MyConfigurationSection
{
[ConfigurationProperty("threads")]
[ConfigurationCollection(typeof(MyThreadCollection), AddItemName="addThread")>
public MyThreadCollection threads { get; }
}
public class MyThreadCollection
{
protected override void CreateNewElement();
protected override object GetElementKey(ConfigurationElement element);
}
public class MyThreadElement
{
[ConfigurationProperty("active", DefaultValue=true, IsRequired=false)>
public bool active { get; set; }
[ConfigurationProperty("batchSize", DefaultValue=10, IsRequired=false)>
public int batchSize { get; set; }
[ConfigurationProperty("system", IsRequired=true)>
public string system { get; set; }
[ConfigurationProperty("department", IsRequired=true)>
public string department { get; set; }
[ConfigurationProperty("connection", IsRequired=true)>
public MyThreadConnectionElement connection { get; set; }
}
public class MyThreadConnectionElement
{
[ConfigurationProperty("server", IsRequired=true)>
public string server { get; set; }
[ConfigurationProperty("database", IsRequired=true)>
public string database { get; set; }
[ConfigurationProperty("timeout", DefaultValue=15, IsRequired=false)>
public int timeout { get; set; }
}
Then I add some elements to the app.config as follows:
<configurationSection>
<threads>
<addThread
active="True"
batchSize="50"
system="MySystem1"
department="Department1">
<connectionString
server="MyServer"
database="Database1" />
</addThread>
<addThread
active="True"
batchSize="30"
system="MySystem2"
department="Department2">
<connectionString
server="MyServer"
database="Database2" />
</addThread>
</threads>
</configurationSection>
Everything works - configuration is read, threads are created, and the processes run.
The problem is, I would like both these threads to have the same system name/value -- both should be MySystem -- but when I do that and run the program, I get a The entry 'MySystem' has already been added. exception.
I figured it might be because a property has to be explicitly configured to allow duplicates, but I don't know how and I couldn't find a property of the ConfigurationProperty class that might allow that, other than IsKey, but from its description it didn't seem like the answer, and trying it didn't solve the problem. Am I on the right track here?
Initially the system property was named name and I though that just maybe any property named name is treated as a unique identifier, so I changed it to system but it didn't change anything.
I tried the <clear /> tag as some other, similar posts suggested, without success.
Do I need to add another hierarchy to the configuration section -- Config -> Department -> Thread instead of Config -> Thread? I'd prefer to not take this approach.
Thanks for any and all input.
I actually found the problem and solution quite some time ago, but forgot to post the answer; thanks #tote for reminding me.
When implementing the ConfigurationElementCollection class, the GetElementKey(ConfigurationElement) method can be overridden. Without immediately realising what the method is for I overrode it and simply returned the system property value, and, since more than one configuration element had the same system name, technically they had the same key, which is why the error occurred.
The solution for me was to return the system and the department values as system.department which resulted in unique keys.
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)
Look at this complex type, which is basically a DTO that wraps some entities. I don't need to track these entities or use the for updating or any of that stuff, I just want to send them down to the client. The stuff at the top are non-entities just to let me know that I'm not crazy.
public class ResultDetail
{
// non entities (some are even complex) - this works GREAT!
public string WTF { get; set; }
public IEnumerable<int> WTFs { get; set; }
public SomethingElse StoneAge { get; set; }
public IEnumerable<SomethingElse> StoneAgers { get; set; }
// these are entities - none of this works
public EntityA EntityA { get; set; }
public IEnumerable<EntityB> EntityB { get; set; }
}
public class SomethingElse
{
public int ShoeString { get; set; }
}
Now look at this:
http://i.snag.gy/tI9O9.jpg
Not a single entity property shows up on the client side generated types. Are there attributes or something that I can or do I really need to create DTO objects for every one of these entity types? There are more than 2 as in my sample and they have many properties.
By the way these entity types have been generated on the client because of the normal query operations in the domain service that work with them.
This is not possible as current Ria services framework is mainly designed for tracking entities, and for Ria services it is not possible to detect which properties to serialized and which to note, since every entity has navigation properties, serializing properties may cause infinite loops or long loops as there is no control over how to navigate object graph.
Instead you are expected to program your client in such way so that you will load relations on demand correctly.
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
I have a usercontrol which is responsible for presenting creation and change of users.
The usercontrol is bound to an entity delivered by a RIA Service:
[MetadataType(typeof(User.UserMetadata))]
public partial class User
{
internal class UserMetadata
{
protected UserMetadata() {}
[Required]
public string Name { get; set; }
[Exclude]
public string PasswordHash { get; set; }
[Exclude]
public int PasswordSalt { get; set; }
[Required]
public string ShortName { get; set; }
[Include]
public IEnumerable<UserRole> UserRoles { get; set; }
}
[DataMember]
[RegularExpression("^.*[^a-zA-Z0-9].*$", ErrorMessageResourceName = "BadPasswordStrength", ErrorMessageResourceType = typeof(ErrorResources))]
[StringLength(25, MinimumLength = 6)]
public string NewPassword { get; set; }
}
When creating a new user, the field "NewPassword" is required - but when changing properties of an existing user, it is not (it is used for password-changes).
What is the best approach to solve this? I have several ideas, but they all feels a little bit crappy :-)
Thanks
It appears you are passing your current passwords back to the GUI. There is no need to ever do that. That would create a potential security hole
Suggest you treat password changing as a separate service call, not just a simple record editing exercise. RIA services supports Invoke Operations which are basically arbitrary direct-calls to your RIA service. The only restriction on Invoke operations is that they cannot return complex types (not a problem for this example).
Pass your current logged-in user identifier, the current password (encoded) and the new password (encoded) and do all the work server side. Return a simple success boolean value.
Just some suggestions, I am happy to see other people's ideas on this one :)