I know when you create a service you can create a generic DataContract:
[DataContract(Name = "Get{0}Request")
public sealed class GetItemRequest<T>
where T : class, new() { ... }
[DataContract(Name = "Get{0}Response")
public sealed class GetItemResponse<T>
where T : class, new() { ... }
[ServiceContract]
public void MyService : IMyService
{
[OperationContract]
GetItemResponse<Foo> GetItem(GetItemRequest<Foo> request);
}
This generates a GetFooRequest and GetFooResponse definition for my WSDL. Now, what I'm curious about is if it is possible to go in the other direction?
Is it possible to create a client that uses the Generic DataContracts and pass those to the server as a concrete object? I attempted this after adding a Service Reference and it didn't really work out so well. So this is more of me wondering if there is any way (even if it means not adding a Service Reference) to do this?
Ultimately, WCF is going to look at the contract class. If that is generated from WSDL/MEX it won't have this (since this isn't how it is expressed in the metadata) - but if your client has the code as above, then sure it should work fine.
If you add a library reference (i.e. a dll / project reference) to your DTO dll from the client, and ensure WCF has shared-assemblies enabled, it should work. If it still baulks, then cheat: use a service reference just to get the config data. Then delete the service reference but keep the configuration (those config files are a pain otherwise). Then it should locate the type from the library.
Related
I'm trying to figure out if there's a way to "Find all references" (using the VS feature, as opposed to Control+F entire solution). when it comes to WCF Data and OperationContracts. In case that is unclear:
namespace WcfTestReferences
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello world");
DoStuff();
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
var results = client.GetData(42);
Console.WriteLine(results);
}
static void DoStuff() { }
}
}
namespace WcfTestReferences.WCFApp
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
}
Solution looks like this:
Now, if I look at DoStuff() with code lens, I can see that it in fact has a reference to it:
But the same does not hold true for the methods being called in the wcf service:
In the above, the only references to the interface/method is the interface/method. I understand that the reference that I was hoping would be there (from the main method):
var results = client.GetData(42);
is not there, because the client is generated, and is not actually my Service1 implementation... but is there a way to change this?
In the real world, we have a WCF layer with thousands of methods, many of which are not used - but I cannot rely on Code Lens/Find all references to make this determination. Is there any way to change this behavior?
because the client is generated, and is not actually my Service1
implementation
This is the root of the problem.
You are correct - there is no way for your code analyser to determine that the GetData() call you are making from your client is semantically the same thing as the GetDate() service operation you have defined on your interface, because from a binary perspective they are defined in two completely different types.
The root of this is that you're using a service reference. WCF provides service references as the default way of connecting to a service, but in my opinion service references are problematic and should be avoided.
Luckily, WCF provides another way of consuming and calling a service via the user of ChannelFactory<T>. One of the many benefits you will get when using this instead of a service reference is that your client will have use of the service interface via a binary reference to the assembly containing your service definition.
This will allow tools like code lens to resolve references to your interface methods directly to your consuming clients.
I'm creating a study project using .net web services and I came across with this problem:
In order to provide for an opportunity to change the web server or even it's nature (it's the part of the task) I created an interface in a separate .dll that every possible (web)services must implement. Say,
public interface IDataAccess
{
// Group of methods which are used for login/logout
bool isUserRegistered(string username);
bool authorize(string username, string password);
//...
}
And I make the web service implement this interface:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Server : System.Web.Services.WebService, IDataAccess
{
//...
}
Then, in the client, I create a reference (namespace WebReference) to this service specifying to reuse type in all assemblies and try to do the following:
private IDataAccess webService = (IDataAccess)(new WebReference.Server());
but this assignment throws exception in runtime stating the convertion can't be done, and, indeed, in the Reference.cs (which is a part of what is created by adding reference to Web Service there is a redeclaration of Server class which doesn't declare IDataAccessImplementation:
public partial class Server : System.Web.Services.Protocols.SoapHttpClientProtocol {
//...
}
So, my question is how to make this reference implement that common interface IDataAccess without manually editting the file Reference.cs?
Firstly, you really don't need to implement the interface on the server side - that will do nothing for the generated code.
Next, note that the declaration is of a partial class. You can use that to your advantage.
All you need to do is create another C# file, which has:
public partial class Server : SoapHttpClientProtocol, IDataAccess {}
That's all you need (in the right namespace and with the right using directives). No code - that's all provided in the generated class. The C# compiler will blend the two declarations, and then you can just use:
private IDataAccess webService = new WebReference.Server();
... or better yet, inject it via a constructor so that you can write tests which don't need to use the real implementation at all!
I am using C# Visual Studio 2012 to create a wcf service.
I had the WSCF.blue tool generate the wsdl from the xsd-s. Then I generated the web service code using the same tool. WSCF.blue does not create a Service Contract and a Data Contract. It creates an interface and a .svc file that contains a class that implements the interface.
When generating the web service code I selected the option to create the abstract classes because I want to be able to keep the implementation of these classes in a separate file.
The abstract class looks like this:
[KnownType(typeof(WebMobileImplementation))]
public abstract class WebMobile : IWebMobile
{
public abstract PutLocationsResponse PutLocations(PutLocationsRequest request);
}
The implementing class (in a different file) looks like this (for now):
public class WebMobileImplementation : WebMobile
{
public override PutLocationsResponse PutLocations(PutLocationsRequest request)
{
PutLocationsResponse response = new PutLocationsResponse();
return response;
}
}
When trying to browse the service I get the message: "Service implementation type is an interface or abstract class and no implementation object was provided"
I thought that adding the knowntype to the implementing class will do the trick but it seems that the implementation is not 'seen' when running the service. What else can I do to 'connect' them?
In WCF 4.0, you can define virtual service activation endpoints that map to your service types in Web.config. This makes it possible to activate WCF services without having to maintain physical .svc files.
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="WebMobile.svc"
service="WebMobileNamespace.WebMobileImplementation"/>
</serviceActivations>
</serviceHostingEnvironment>
I'm subcsribing to the SQL Server 2008 SSRS web service ( .../reportserver/ReportService2005.asmx?wsdl) using WCF, with default WCF config options as far as I can tell.
It does something weird when it generates the local proxy classes though.
I'll use the ListChildren method as an example:
On the client side, WCF generates an interface like this, as you would expect:
public interface ReportingService2005Soap {
ListChildrenResponse ListChildren(ListChildrenRequest request);
}
It also generates a 'client' proxy that implements that interface:
public partial class ReportingService2005SoapClient :
System.ServiceModel.ClientBase<ReportingService2005Soap>, ReportingService2005Soap
{
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
ListChildrenResponse ReportingService2005Soap.ListChildren(ListChildrenRequest request)
{
return base.Channel.ListChildren(request);
}
public ServerInfoHeader ListChildren(string Item, bool Recursive, out CatalogItem[] CatalogItems) {
ListChildrenRequest inValue = new ListChildrenRequest();
inValue.Item = Item;
inValue.Recursive = Recursive;
ListChildrenResponse retVal = ((ReportingService2005Soap)(this)).ListChildren(inValue);
CatalogItems = retVal.CatalogItems;
return retVal.ServerInfoHeader;
}
}
As you can see, the client proxy implements the interface and then 'hides' it from being used by explicitly implementing the interface (so you have to cast to get to the interface method) and additionally with a EditorBrowsableState.Advanced attribute.
It then adds an extra wrapper method that uses 'out' parameters.
Is there a way to stop if from doing that, and just have it implement the interface directly?
What its doing here leads you down the path of using the wrapper methods with 'out' parameters, and then you find you can't mock the service very easily because the wrapper methods aren't virtual, and aren't defined in any interface.
NB: I'm using the SSRS web service as an example here but I've seen WCF do this on other services as well.
This probably happens if your service is using MessageContracts. Proxy creation by default tries to unwrap these message contracts so that exposed operations accept their content directly. If you want to use message contracts on the client as well you need to configure it in advanced settings of Add service reference by checking Always generate message contracts.
My goal is to load an external class in a running application environment (like a plugin model). Creating an instances of the class in an running environment is not the problem (the classes using an Interface). The problem is to get the class which must be available from a central WCF services.
Is it possible to transport an class or assembly to the client by using WCF?
Something like this:
[ServiceContract]
public interface ISourceData
{
[OperationContract]
xxx GetClassData { get; set; } // <-- here to get data the class to app can create an instances of this
}
I hope that you understand my situation. Thanks.
First of all, the attribute in your sample above must be OperationContract, not DataContract. The DataContract attribute is for the class that you want to return in GetClassData.
The problem in your situation is that on the client side the class itself is not replicated when you add the service reference, but a stub is generated for the properties that you define in your DataContract. So you get the data, but not the logic.
You could now create an assembly which defines the data classes to be exchanged and add them to both the service and the client, but as I understand your question, you want to dynamically load assemblies in the service and send these "implementations" to the client without the client actually having access to the DLL that implements the class. This may not be possible in an easy way.
EDIT
Re-reading your question I now understand that you do not want to "transfer an instance", but you want to transfer the class definition. One way would be to actually transfer the source code for the class and try to use Reflection.Emit to create a dynamic assembly. A sample of this can be found here.
Yes , you can .
and also you must to define the type of your class like ↓
[ServiceKnownType(typeof(xxx))]
public interface IService
I think you need the assembly on the client so you need to transfer the dll containing the assembly to the client, then have the client save it in a plugins directory for the app and have the app and load it from there.
Although I image that this is going to be a permissions nightmare to get the app to be able to use the dlls downloaded from the service.
You would mark up the classes used in your interface like this:
[ServiceContract]
public interface ISourceData
{
[OperationContract]
MyClass GetClassData();
}
[DataContract]
public class MyClass
{
[DataMember]
public string MyMember1 {get; set;} // included in transport
public int MyMember2 {get; set;} // not included
}