webservice method overload possible issues with non .net webservices - wcf

I am designing a web service which has overloaded method and someone said we should try not to overload methods in web service as there can be issues generating wsdl or if non .net service tries to consume those methods.
I tested the scenario of generating the wsdl by creating a simple service with two add methods one taking integer and other double and had no issues.
so wanted to check
1. if i am missing something in the wsdl which i am overlooking.
2. Are there any known issues with non .net webservice cosuming service with overloaded functions.
3.Is it not recommended to use overloaded functions if you can?
following is what my test service looks like
--service library
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace EvalServiceLibrary
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class EvalService: IEvalService
{
public int AddEval(int a, int b, int c)
{
return a + b + c;
}
public double AddEval(double a, double b, double c)
{
return a + b + c;
}
}
}
--inerface code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace EvalServiceLibrary
{
[ServiceContract]
public interface IEvalService
{
[OperationContract(Name = "Addint")]
int AddEval(int a, int b, int c);
[OperationContract(Name = "Addfloat")]
double AddEval(double a, double b, double c);
}
}
--service code
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace EvalServiceLibrary
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class EvalService: IEvalService
{
public int AddEval(int a, int b, int c)
{
return a + b + c;
}
public double AddEval(double a, double b, double c)
{
return a + b + c;
}
}
}

You will not have problems since OperationContract has different name for each operation (this is the name that counts). WSDL consumers will have no idea that you use an overload for implementation. You can also open the WSDL and see those are two distinguished operations.

Related

Why am I getting null data on wcf deserialization?

I've a system where I'm exchanging messages across different point to point comms channels- between Windows and embedded systems, and have done it all as pretty standard custom serialize/deserialize functions pretty much entirely done by hand, since that makes it easy to port between C# on the Windows side and C on the embedded.
Now I want to add a chunk that communicates between PCs on the net at large. Rather than do another batch of the same stuff, use TcpClient/TcpListener and keep track of overlapping messages and responses, I decided to have a look at WCF.
After looking at lots of messages on here, and docs etc elsewhere, I've come up with a very simple app that exchanges messages, with the server containing one function that takes and returns an interface instance, rather than a fixed class. Even though the example has only one kind of message- hence only one type is set using the KnownType and ServiceKnownType attributes, I picture there being a few tens of different types of messages that could be sent, and I want to be able to add them fairly easily as things evolve.
Although no errors are generated by the code, the object that's instantiated at the far end has none of the data that was sent. I've tried packet sniffing to see if I can confirm the data's actually going on the wire but I can't understand the wire protocol. So I don't know if the data's disappearing in the client on transmission or in the server. If I change the code to use instances of TestMessageType directly rather than using the interface, it works fine.
The solution's made of three projects; a "types" assembly and then client and server console apps that reference that assembly. The types assembly contains this code;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace WCF_TCP_Sandpit
{
public interface ITestInterface
{
Int64 I64Value {get; set;}
}
[ServiceContract]
public interface IServer
{
[OperationContract]
[ServiceKnownType(typeof(TestMessageType))]
ITestInterface Test(ITestInterface msg);
}
[DataContract]
[KnownType(typeof(TestMessageType))]
public class TestMessageType : ITestInterface
{
Int64 _v1;
public long I64Value
{
get { return _v1; }
set { _v1 = value; }
}
public static Type[] KnownTypes()
{
return new Type[] { typeof(TestMessageType) };
}
}
}
The server code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using WCF_TCP_Sandpit;
using System.Runtime.Serialization;
namespace Server
{
class Program : IServer
{
static void Main(string[] args)
{
using (ServiceHost serviceHost = new ServiceHost(typeof(Program), new Uri("net.tcp://127.0.0.1:9000")))
{
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
#region IServer Members
public ITestInterface Test(ITestInterface msg)
{
ITestInterface reply = new TestMessageType();
reply.I64Value = msg.I64Value * 2;
return reply;
}
#endregion
}
}
and the client code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCF_TCP_Sandpit;
using System.ServiceModel;
namespace Client
{
class Program
{
static void Main(string[] args)
{
ITestInterface m,r;
int i = 0;
ChannelFactory<WCF_TCP_Sandpit.IServer> srv
= new ChannelFactory<WCF_TCP_Sandpit.IServer>
(new NetTcpBinding(), "net.tcp://127.0.0.1:9000");
WCF_TCP_Sandpit.IServer s;
s = srv.CreateChannel();
while (true)
{
m = new WCF_TCP_Sandpit.TestMessageType();
m.I64Value = i++;
r = s.Test(m);
Console.WriteLine("Sent " + m.I64Value + "; received " + r.I64Value);
System.Threading.Thread.Sleep(1000);
}
}
}
}
Can anyone cast some light on what's going wrong?
Don't you need the DataMember attribute on your I64Value property?

DataContract Attributes not being sent in responses

I have had it where the name/namespace/other attributes show up when sending a request, but now they have disappeared and cant figure out for the life of me what changed... I am trying to utilize the WebApi project but the documentation seems limited.
WebServiceResource.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel;
using System.ServiceModel.Web;
using wsDAL.EDataTypes;
using System.Data;
using System.IO;
using System.Text;
using System.Net.Http;
namespace wsDAL
{
[ServiceContract]
public class WebServiceResources
{
[WebGet(UriTemplate = "/GetNameValueTest/{name}/{value}")]
public NameValue GetNameValueTest(string name, string value)
{
NameValue nv = new NameValue("WS_" + name + "_WS", "WS_" + value + "_WS");
return nv;
}
}
}
GeneralResources.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.Data;
namespace wsDAL.EDataTypes
{
[DataContract(Name = "NameValueContract", Namespace = "http://fred.NameValue.com")]
public class NameValue
{
private string _name;
private string _value;
public NameValue()
{
_name = null;
_value = null;
}
public NameValue(string Name, string Value)
{
_name = Name;
_value = Value;
}
[DataMember(Name = "NameMember")]
public string Name { get { return _name; } set { _name = value; } }
[DataMember(Name = "ValueMember")]
public string Value { get { return _value; } set { _value = value; } }
}
}
Note I am using lightcore as an IOC container (kinda new to this stuff)
Was originally going of the post at http://blog.alexonasp.net/post/2011/04/15/Microsoft-Web-API-e28093-the-REST-is-done-by-WCF-(Part-1).aspx
but once I got to part six where he is returning HttpResponseMessage<Contact> from POSTs, it all started falling apart. client was looking for the namespace when returning xml but that was not part of the serialized response...
Global.asax.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using LightCore;
using Microsoft.ApplicationServer.Http.Description;
using Microsoft.ApplicationServer.Http.Activation;
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
ContainerBuilder builder = new ContainerBuilder();
builder.Register<IResourceFactory, LightCoreResourceFactory>();
IContainer container = builder.Build();
var configuration = HttpHostConfiguration.Create().SetResourceFactory((serviceType, instanceContext, request) => container.Resolve(serviceType), null);
RouteTable.Routes.MapServiceRoute<WebServiceResources>("ws", configuration);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
....
Ok, what it seems that I failed to realize, is that the name/namespace info gets serialized to the server, but not to the client.
Have you added a routing table record?
RouteTable.Routes.MapServiceRoute<WebServiceResources>("GetNameValueTest");
Updated answer on this... I was using a DataContractSerializer on the client which was adding the name/namespace info, while on the server I was using the default WebApi serialization which was not adding the info. Thanks for anyone who took time looking into this.

WCF Service Creation

I am trying to build a small WCF service and wanted to utilize it in a test application.
PFB service code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace HelloIndigo
{
[ServiceContract(Namespace="http://www.thatindigoirl.com/samples/2006/06")]
public interface IHelloIndigoService
{
[OperationContract]
string HelloIndigo();
}
public class HelloIndigoService : IHelloIndigoService
{
public string HelloIndigo()
{
return "Hello indigo";
}
}
}
Host Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService), new Uri("http://localhost:8000/HelloIndigo")))
{
host.AddServiceEndpoint(typeof(HelloIndigo.IHelloIndigoService), new BasicHttpBinding(), #"HelloIndigoService");
host.Open();
Console.WriteLine("Press <ENTER> to terminate the service hosy");
Console.ReadLine();
}
}
}
}
Whenever I am trying to run Host I am getting below mentioned error in host.Open() statement.
HTTP could not register URL
http://+:8000/HelloIndigo/. Your
process does not have access rights to
this namespace (see
http://go.microsoft.com/fwlink/?LinkId=70353
for details).
Can anyone help me with this
You need to run the host app with elevated privileges (i.e., "As Administrator"). Under Vista/Win7, only administrative accounts have the permission to register socket listeners.

SilverLight Enabled Wcf Service - can't keep track of session

I'm new to Silverlight and WCF services. I'm trying to write a client application that can manipulate an object server side.
My problem is that each time my Silverlight client makes a call to the service, it enters into the constructor systematically
public SilverLightEnabledWcfService()
{
}
In the below example, I simply want to increment or decrement a number depending on the activity client side.
How am I supposed to do this properly?
I also tried to create a regular ASP.net client page and I got the same result, ie the server doesn't remember the session. So I don't think the problem is in my client, but I'm still happy to post the code if it helps.
Thanks !!
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Count.Library;
namespace Count.WebApp
{
[ServiceContract(Namespace = "")]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class SilverLightEnabledWcfService
{
public SilverLightEnabledWcfService()
{
}
private Class1 _class1;
[OperationContract]
public int Add1()
{
if (_class1 == null)
_class1 = new Class1(0);
_class1.Add1();
return Value;
}
[OperationContract]
public int Remove1()
{
if (_class1 == null)
_class1 = new Class1(0);
_class1.Remove1();
return Value;
}
public int Value
{
get
{
return _class1.Count;
}
}
}
}
Sessions require the wsHttpBinding, but this is not supported by Silverlight. There are workarounds, though:
http://web-snippets.blogspot.com/2008_08_01_archive.html
http://forums.silverlight.net/forums/t/14130.aspx

WCF Relocation of DataContracts

This is a fully functional WCF Hello World program. I.e. I am able to run this program without any Exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace DataContractsNamespace
{
[DataContract]
public class AccountInfo
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace Clients
{
public class BankProxy : ServiceContractsNamespace.IBank
{
ServiceContractsNamespace.IBank channel;
public BankProxy()
{
channel = ChannelFactory<ServiceContractsNamespace.IBank>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:8000/Services/BankService"));
}
public decimal GetAcccountBalance(string AcctNo)
{
return channel.GetAcccountBalance(AcctNo);
}
public DataContractsNamespace.AccountInfo GetAccountInfo(string AcctNo)
{
return channel.GetAccountInfo(AcctNo);
}
}
}
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
namespace ServiceContractsNamespace
{
[ServiceContract]
public interface IBank
{
[OperationContract]
decimal GetAcccountBalance(string AcctNo);
[OperationContract]
DataContractsNamespace.AccountInfo GetAccountInfo(string AcctNo);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Clients
{
class Program
{
static void Main(string[] args)
{
BankProxy prox = new BankProxy();
Console.WriteLine("Hit enter to invoke the service call. Type exit then enter to close");
while (Console.ReadLine() != "exit")
{
string balance = prox.GetAcccountBalance("1234").ToString("c");
DataContractsNamespace.AccountInfo ai = prox.GetAccountInfo("1234");
Console.WriteLine("{0} {1} your account balance is {2}.", ai.FirstName, ai.LastName, balance);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Hosts
{
public class BankService : ServiceContractsNamespace.IBank
{
public decimal GetAcccountBalance(string AcctNo)
{
return 1.37m;
}
public DataContractsNamespace.AccountInfo GetAccountInfo(string AcctNo)
{
DataContractsNamespace.AccountInfo ai = new DataContractsNamespace.AccountInfo();
ai.FirstName = "Paul";
ai.LastName = "Johansen";
return ai;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
namespace Hosts
{
class Program
{
static void Main(string[] args)
{
ServiceHost servHo = new ServiceHost(typeof(BankService), new Uri("http://localhost:8000/Services"));
servHo.AddServiceEndpoint(typeof(ServiceContractsNamespace.IBank), new BasicHttpBinding(), "BankService");
servHo.Open();
Console.WriteLine("This service is open for business. Hit Enter to close.");
Console.ReadLine();
servHo.Close();
}
}
}
As you can see, AccountInfo - Data contract is shared by both Client and Host.
I need to keep data contract only to Host/Service side.
Clients should only see interfaces of DataContracts (like IAccountInfo).
How should I modify my program to introduce IAccountInfo?
It sounds like you want to return an interface instead of a class. I'm not exactly sure why you are not content to return AccountInfo. However, you should be able to do this but you will need to use a KnownType or perhaps ServiceKnownType to make it work.
Alternately, if you are working in a fully .NET environment you can use the NetDataContractSerializer instead of the DataContractSerializer.
For reference and examples you can check out:
http://nirajrules.wordpress.com/2009/08/26/wcf-serializers-xmlserializer-vs-datacontratserializer-vs-netdatacontractserializer/
http://www.pluralsight.com/community/blogs/aaron/archive/2006/04/21/22284.aspx
http://weblogs.asp.net/avnerk/archive/2006/07/31/WCF-Serialization-part-1_3A00_-Interfaces_2C00_-Base-classes-and-the-NetDataContractFormatSerializer.aspx
http://www.thoughtshapes.com/WCF/ExampleTwo.htm
And what should IBank.GetAccountInfo return to client if you don't want to share AccountInfo? create 2 classes make the first datacontract the second not, and where you want to share use the first one, where not, the second one