How to migrate .Net Framework service reference to .Net Standard service reference - wcf

We're migrating our old .Net Framework code to .Net Standard. One of the projects had a wcf service reference that I was able to recreate in the new .Net Standard project. However, the generated code is different in that the old one had the following with an empty constructor for the object, while the .Net Standard one does not. Is there a common workflow for converting this so I can have an empty constructor in the new version?
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class TasksClient : System.ServiceModel.ClientBase<WebServiceProxy.Tasks.ITasks>, WebServiceProxy.Tasks.ITasks {
public TasksClient() {
}
public TasksClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public TasksClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}....
The new one looks like this.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.0.3")]
public partial class TasksClient : System.ServiceModel.ClientBase<Tasks.ITasks>, Tasks.ITasks
{
public TasksClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}

Related

service reference is ignoring knowntype

[CollectionDataContract(Namespace = "CISICPD")]
[KnownType(typeof(List<CISICPD.LeeDictionary>))]
public class LeeDictionary : Dictionary<string, object>
{
}
[DataContract(Namespace = "CISICPD")]
[KnownType(typeof(List<CISICPD.LeeDictionary>))]
public class TestResponse
{
[DataMember]
public List<LeeDictionary> Results;
public TestResponse() { Results = new List<LeeDictionary>(); }
[OnDeserializing]
private void OnDeserialize(StreamingContext c) { Results = new List<LeeDictionary>(); }
}
if the above is used in a service reference the generated reference.cs simply ignores the knowntypes specified above.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="TestResponse", Namespace="CISICPD")]
[System.SerializableAttribute()]
public partial class TestResponse : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
I specified the LeeDictionary so i could set my own namespace (thought it might be namespace issues), changing it to Dictionary<string,object> is just the same. The problem comes when the dictionary itself contains another dictionary and complains that the type is not known.
If I add the knowntype line to the reference.cs it then all works but I cant see why it wont put it in when generating the references?

Self-host (No IIS or WAS) WCF with a service that requires parameters

Hopefully this is an easy one. I'm wondering if this is possible - perhaps it is not. I'm attempting to self-host a WCF service (in my example below it is a console application). The service does not have a default constructor. It only contains a single parameter signature constructor. I need the service to be able to handle user sessions. Currently I am using Ninject DI. Here is a simple code solution I came up with to demonstrate my issue:
using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using Ninject.Modules;
namespace ConsoleApplication1
{
public class Program
{
static void Main()
{
using (var webServiceHost = new WebServiceHost(typeof(MyWcf)))
{
var webHttpBinding = new WebHttpBinding();
var uri = new Uri("http://localhost:8000/");
webServiceHost.AddServiceEndpoint(typeof(IMyWcf), webHttpBinding, uri);
webServiceHost.Open();
Console.WriteLine("Service is ready...");
Console.ReadKey();
}
}
}
[ServiceContract]
public interface IMyWcf
{
[OperationContract, WebGet(UriTemplate = "")]
string HelloWorld();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyWcf : IMyWcf
{
private readonly IMessage _customMessage = new Message("Default Message.");
public MyWcf(IMessage message)
{
_customMessage = message;
}
public string HelloWorld()
{
return _customMessage.Text;
}
}
public interface IMessage
{
string Text { get; }
}
public class Message : IMessage
{
public Message (string message)
{
Text = message;
}
public string Text { get; set; }
}
public class NinjectSetup : NinjectModule
{
public override void Load()
{
Bind<IMessage>().To<Message>()
.WithConstructorArgument("message", "Injected String Message.");
}
}
}
Obviously commenting out the parameterized constructor allows the service to run. But that does me no good. I don't want to use ServiceHostFactory because that apparently requires me to have a .svc/IIS. Is there a way around this? Can I just create a new MyWebServiceHost that inherits from WebServiceHost and override some method that will create a instance for the service?
Using Ruben's suggestion (in the comments) above, I was able to locate a working example within the Ninject.Extensions.Wcf source repository.

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.

Type not exposed by WCF Service

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))]

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