Type not exposed by WCF Service - wcf

I have a small test web service to emulate something odd I'm noticing in a real world app. As the demo shows the same behaviour as the app I will use the demo for brevity.
In short My service interface file looks as follows (as you can see it is the default WCF service created by VS2008 but I have added a new public method (GetOtherType()) and two new classes at the bottom (SomeOtherType and SomeComplexType). SomeOtherType manages a generic List of type SomeComplexType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCFServiceTest
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[OperationContract]
SomeOtherType GetOtherType();
}
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
[DataContract]
public class SomeOtherType
{
public List<SomeComplexType> Items { get; set; }
}
[DataContract]
public class SomeComplexType
{
}
}
My Service is implemented as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCFServiceTest
{
public class Service1 : IService1
{
#region IService1 Members
public string GetData(int value)
{
throw new NotImplementedException();
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
throw new NotImplementedException();
}
#endregion
#region IService1 Members
public SomeOtherType GetOtherType()
{
throw new NotImplementedException();
}
#endregion
}
}
The problem I have is that if I include a service reference to this service in an ASP.NET Web Application, I cannot see SomeComplexType via intellisense. The error relates to the type or namespace cannot be found. However, SomeOtherType can be found (I'm assuming as the type is a return type from one of the public methods).
Am I right in thinking I can't expose a type from a WCF Service if that type is not featured in the method signature of one of my public methods (either return type or argument)? If so, how would I be able to iterate over the Items inside an instance of SomeOtherType on the client?
Many Thanks and I hope this is clear.
Simon

The problem I have is that if I
include a service reference to this
service in an ASP.NET Web Application,
I cannot see SomeComplexType via
intellisense. The error relates to the
type or namespace cannot be found.
However, SomeOtherType can be found
(I'm assuming as the type is a return
type from one of the public methods).
Am I right in thinking I can't expose
a type from a WCF Service if that type
is not featured in the method
signature of one of my public methods
(either return type or argument)? If
so, how would I be able to iterate
over the Items inside an instance of
SomeOtherType on the client?
You are absolutely right - your SomeComplexType is never used in any of the service methods, and it's also never tagged as a [DataMember] in any of the types that are indeed used as parameters in your service methods. Therefore, from the point of view of WCF, it's not needed, and won't show up in the WSDL/XSD for the service.
As Graham already pointed out - you are using the SomeComplexType in one place:
[DataContract]
public class SomeOtherType
{
public List<SomeComplexType> Items { get; set; }
}
but since the Items element is not tagged as a [DataMember], it (and therefore the type it uses) will not be included in the WSDL/XSD of your service. Since the Items are not marked as DataMember, they won't be in your serialized WCF message either, so you won't ever need to iterate over this collection :-)
So most likely, what you really want, is just add the [DataMember] attribute to your Items property; then it'll be included in the WSDL/XSD, and so will the SomeComplexType.

Looks like you need the [DataMember] attribute on your SomeOtherType.Items property, i.e.
[DataMember]
public List<SomeComplexType> Items { get; set; }

I'm not at all an expert on this topic, so just as a shot in the blue: Empty DataContracts are discarded by WCF? Try exposing anything in ComplexDataType (some int is enough) and see if that changes anything.
Also, I believe you can verify the availability of the type using the built-in wcftestclient (you need to turn metadata exchange on for this).

We can use Known type in Service in order to get exposed of the class and its members when it is not used in the operation contract signature directly or indirectly.

For such types where you just want it to be available on the client side even if its not used, below attribute class is handy to make it available on client side.
[KnownType(typeof(SomeComplexType))]

Related

Error accessing a WCF service

I have a very strange problem.
I have a working WCF service.
[ServiceContract]
public interface IService
{
[OperationContract]
int AddResult(int result, string name);
[OperationContract]
int list(int count);
}
In another class I have the implementation of this service. And it works.
But when I change the method "list" like this:
[ServiceContract]
public interface IService
{
[OperationContract]
int AddResult(int result, string name);
[OperationContract]
List<string> list(int count);
}
When I add service reference from targeted project (it is a Windows Phone application) I receive several errors and warnings. The key idea of them is that the service cannot be loaded (or endpoints can not be loaded).
The difference between two methods is very small - List instead of int type. But it is crucial.
Why it is so? Why I can not use List?
did you try to encapsulate your List collection into a proxy class? You could try something like:
[DataContract]
public class MyData
{
[DataMember]
public List<string> list { get; set; }
}
[ServiceContract]
public interface IService
{
[OperationContract]
int AddResult(int result, string name);
[OperationContract]
MyData list(int count);
}
Also, take a look at this link, I think that it might be what you are looking for.
UPDATE
As per discussed on the comments section of this thread, the problem was not located in the WCF service itself, but on the client that was being generated in #user1460819 Windows Phone app.
This problem was solved after the WCF Service binding was changed to "basicHttpBinding", the WCF reference on the client side was regenerated and the whole project was rebuilt.

DataContract composite Class

I have a problem with serialization composite class (using WCF Service).
here my class in namespace1 (it is not in service namespace) :
[DataContract]
public class UpData
{
[DataMember]
public double Version ;
public UpData()
{
this.Version = -1;
}
}
In my Service namespace (in interface) I deсlare this procedure :
ArrayList GetDownloadPath(Dictionary<string,string> lib1, Dictionary<string,string> lib2);
ArrayList contains UpData objects.
I have error(
How will be right to send ArrayList of UpData objects? (may be specific DataContract?)
Thanks a lot!
I'm not sure if ArrayList is serializable by default. Using a generic list could solve your problem:
[OperationContract]
List<UpData> GetDownloadPath(Dictionary<string,string> lib1, Dictionary<string,string> lib2);
EDIT: I think you also need to specify a getter and setter for your Version property, i.e.
[DataContract]
public class UpData
{
[DataMember]
public double Version { get; set; }
public UpData()
{
this.Version = -1;
}
}
More info here.

How to access custom attributes defined in WCF service using C#?

First question is, how can I get the type of an object stored in a variable? Generally we do:
Type t = typeof(ClassName); //if I know the class
but, how can I say something:
Type t = typeof(varClassName); //if the class name is stored in a variable
Second question, a broader picture is, I have a WCF service that contains a DataContract class say "MyClass" and I have defined a custom attribute called "MyAttribute" to it. There is one method say "GetDataUsingDataContract" with a parameter of type MyClass. Now on client, I invoke the webservice. I use MethodInfo and ParameterInfo classes to get the parameters of the method in question. But how can I access the attributes of the method parameter which is actually a class Myclass? Here is the code that I tried:
MyService.Service1Client client = new MyService.Service1Client();
Type t = typeof(MyService.Service1Client);
MethodInfo members = t.GetMethod("GetDataUsingDataContract");
ParameterInfo[] parameters = members.GetParameters();
foreach (var parameter in parameters)
{
MemberInfo mi = parameter.ParameterType; //Not sure if this the way
object[] attributes;
attributes = mi.GetCustomAttributes(true);
}
Above code doesn't retrieve me the custom attribute "MyAttribute". I tried the concept in the class that is defined in the same project and it works. Please HELP!
but, how can I say something:
Type t = typeof(varClassName); //if the class name is stored in a variable
Try
Type.GetType("varClassName", false, true);
As to your second question:
Above code doesn't retrieve me the
custom attribute "MyAttribute". I
tried the concept in the class that is
defined in the same project and it
works. Please HELP!
Just guessing, I'm not sure that attributes are exposed to the client, by default. I think its the same issue as an untrusted assembly. Some attributes are sensitive info. See this:
http://blogs.msdn.com/b/haibo_luo/archive/2006/02/21/536470.aspx
But you could try linking the service project types into your app by first referencing the service assembly in your client project, then going to your service reference -> "Configure Service Reference" and selecting "Reuse types in all referenced assemblies". I'm not sure this option will affect the service interface classes, but I use it often with my domain objects. Worth a try.
Type mi = parameter.ParameterType; //Not sure if this the way
object[] attributes;
attributes = mi.GetCustomAttributes(true);
Ensure your proxy class has knowledge on attributes
Hope this will help
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Reflection;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
StartService();
}
string url = "http://localhost:234/MyService/";
private void StartClient()
{
IMyService myService = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress(url));
Type t = typeof(IMyService);
MethodInfo members = t.GetMethod("MyMethod");
ParameterInfo[] parameters = members.GetParameters();
foreach (var parameter in parameters)
{
Type mi = parameter.ParameterType;
object[] attributes;
attributes = mi.GetCustomAttributes(true);
}
}
private void StartService()
{
ServiceHost host = new ServiceHost(typeof(MyService), new Uri(url));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
}
private void button1_Click(object sender, EventArgs e)
{
StartClient();
}
}
[AttributeUsage(AttributeTargets.Interface)]
public class MyAttrib : Attribute
{
}
[MyAttrib]
public interface IMyContract
{
string Name { get; set; }
}
[DataContract]
public class MyContract : IMyContract
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract]
public interface IMyService
{
[OperationContract]
bool MyMethod(IMyContract dummy);
}
[ServiceBehavior(UseSynchronizationContext = false)]
public class MyService : IMyService
{
public bool MyMethod(IMyContract dummy)
{
return true;
}
}
}

Wcf inhereted models

[DataContract]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}
[ServiceContract]
interface IService
{
[OperationContract]
void SetValue (Base base);
}
is there a way to use the service like the following style:
new Service ().SetValue (new A ());
You tagged this WCF so I assume you want to use it.
You need to connect to the endpoint using the ChannelFactory and then open the channel.
This will not work:
new Service ().SetValue (new A ());
You need to do smth. like this:
using (var scf = new ChannelFactory< IService >(<Binding>,<EndpointAddress>)
{
IService proxy = scf.CreateChannel();
proxy.SetValue(new (A));
}
This will return you a proxy object that implements the IService interface. You can call the SetValue on this object.
As well as changing the way you're calling the service as indicated by #Flo, you'll also need to make a small change to prepare the Data Contract Serializer to deal with the inheritance hierarchy.
The easiest way of doing this is decorating Base with the KnownTypeAttribute. Like this,
[DataContract]
[KnownType(typeof(A))]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}

use svcutil to map multiple namespaces for generating wcf service proxies

I want to use svcutil to map multiple wsdl namespace to clr namespace when generating service proxies. I use strong versioning of namespaces and hence the generated clr namespaces are awkward and may mean many client side code changes if the wsdl/xsd namespace version changes. A code example would be better to show what I want.
// Service code
namespace TestService.StoreService
{
[DataContract(Namespace = "http://mydomain.com/xsd/Model/Store/2009/07/01")]
public class Address
{
[DataMember(IsRequired = true, Order = 0)]
public string street { get; set; }
}
[ServiceContract(Namespace = "http://mydomain.com/wsdl/StoreService-v1.0")]
public interface IStoreService
{
[OperationContract]
List<Customer> GetAllCustomersForStore(int storeId);
[OperationContract]
Address GetStoreAddress(int storeId);
}
public class StoreService : IStoreService
{
public List<Customer> GetAllCustomersForStore(int storeId)
{
throw new NotImplementedException();
}
public Address GetStoreAddress(int storeId)
{
throw new NotImplementedException();
}
}
}
namespace TestService.CustomerService
{
[DataContract(Namespace = "http://mydomain.com/xsd/Model/Customer/2009/07/01")]
public class Address
{
[DataMember(IsRequired = true, Order = 0)]
public string city { get; set; }
}
[ServiceContract(Namespace = "http://mydomain.com/wsdl/CustomerService-v1.0")]
public interface ICustomerService
{
[OperationContract]
Customer GetCustomer(int customerId);
[OperationContract]
Address GetStoreAddress(int customerId);
}
public class CustomerService : ICustomerService
{
public Customer GetCustomer(int customerId)
{
throw new NotImplementedException();
}
public Address GetStoreAddress(int customerId)
{
throw new NotImplementedException();
}
}
}
namespace TestService.Shared
{
[DataContract(Namespace = "http://mydomain.com/xsd/Model/Shared/2009/07/01")]
public class Customer
{
[DataMember(IsRequired = true, Order = 0)]
public int CustomerId { get; set; }
[DataMember(IsRequired = true, Order = 1)]
public string FirstName { get; set; }
}
}
1. svcutil - without namespace mapping
svcutil.exe /t:metadata
TestSvcUtil\bin\debug\TestService.CustomerService.dll
TestSvcUtil\bin\debug\TestService.StoreService.dll
svcutil.exe /t:code *.wsdl *.xsd /o:TestClient\WebServiceProxy.cs
The generated proxy looks like
namespace mydomain.com.xsd.Model.Shared._2009._07._011
{
public partial class Customer{}
}
namespace mydomain.com.xsd.Model.Customer._2009._07._011
{
public partial class Address{}
}
namespace mydomain.com.xsd.Model.Store._2009._07._011
{
public partial class Address{}
}
The client classes are out of any namespaces. Any change to xsd namespace would imply changing all using statements in my client code all build will break.
2. svcutil - with wildcard namespace mapping
svcutil.exe /t:metadata
TestSvcUtil\bin\debug\TestService.CustomerService.dll
TestSvcUtil\bin\debug\TestService.StoreService.dll
svcutil.exe /t:code *.wsdl *.xsd /n:*,MyDomain.ServiceProxy
/o:TestClient\WebServicesProxy2.cs
The generated proxy looks like
namespace MyDomain.ServiceProxy
{
public partial class Customer{}
public partial class Address{}
public partial class Address1{}
public partial class CustomerServiceClient{}
public partial class StoreServiceClient{}
}
Notice that svcutil has automatically changed one of the Address class to Address1. I don't like this. All client classes are also inside the same namespace.
What I want
Something like this:
svcutil.exe
/t:code *.wsdl *.xsd
/n:"http://mydomain.com/xsd/Model/Shared/2009/07/01, MyDomain.Model.Shared;http://mydomain.com/xsd/Model/Customer/2009/07/01, MyDomain.Model.Customer;http://mydomain.com/wsdl/CustomerService-v1.0, MyDomain.CustomerServiceProxy;http://mydomain.com/xsd/Model/Store/2009/07/01, MyDomain.Model.Store;http://mydomain.com/wsdl/StoreService-v1.0, MyDomain.StoreServiceProxy"
/o:TestClient\WebServiceProxy3.cs
This way I can logically group the clr namespace and any change to wsdl/xsd namespace is handled in the proxy generation only without affecting the rest of the client side code.
Now this is not possible. The svcutil allows to map only one or all namespaces, not a list of mappings.
I can do one mapping as shown below but not multiple
svcutil.exe
/t:code *.wsdl *.xsd
/n:"http://mydomain.com/xsd/Model/Store/2009/07/01, MyDomain.Model.Address"
/o:TestClient\WebServiceProxy4.cs
But is there any solution. Svcutil is not magic, it is written in .Net and programatically generating the proxies. Has anyone written an alternate to svcutil or point me to directions so that I can write one.
You can do multiple namespace mappings by providing additional namespace parameters -- not by semi-colon seperating them. So your example should instead be
svcutil.exe /t:code *.wsdl *.xsd
/n:http://mydomain.com/xsd/Model/Shared/2009/07/01,MyDomain.Model.Shared
/n:http://mydomain.com/xsd/Model/Customer/2009/07/01,MyDomain.Model.Customer
/n:http://mydomain.com/wsdl/CustomerService-v1.0,MyDomain.CustomerServiceProxy
/n:http://mydomain.com/xsd/Model/Store/2009/07/01,MyDomain.Model.Store
/n:http://mydomain.com/wsdl/StoreService-v1.0,MyDomain.StoreServiceProxy
/o:TestClient\WebServiceProxy3.cs
Although, I am currently having trouble where the types generated from .xsd files are not affected by these namespaces. Only the types generated from the .wsdl files are. The documentation implies that both should be.
Just in case you want to map all schema namespaces to one CLR namespace then :
SvcUtil "your wsdl file.xml" /n:*,RequiredClrNamespace