Combining WCF SOAP and REST - c#

The REST project works fine, this can be accessed through this address:
http://localhost:8525/Device/Login?deviceID=testid&password=a&serialNum=testserial
I also have WCF SOAP project in my REST project, these two projects are separated in different folders, "SOAP" and "REST".
My problem is that, after I put this code:
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("Device", new WebServiceHostFactory(), typeof(Rest.DeviceComponent)));
}
I can't access now the SOAP service which I was able to access before through this address:
http://localhost:8525/DeviceComponent.svc (using WCFTest Client)
Here is the WebConfig
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<standardEndpoints>
<webHttpEndpoint>
<!--
Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
via the attributes on the <standardEndpoint> element below
-->
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
<handlers>
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd"/>
</handlers>
</system.webServer>
</configuration>
And inside Global.asax.cs
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("Device", new WebServiceHostFactory(), typeof(Rest.DeviceComponent)));
}
SOAP sample contract
namespace TSDEVICE.SoapSVC.Interface
{
[ServiceContract]
public interface IDeviceComponent
{
[OperationContract]
Session Login(string deviceID, string password, string serialNum, string ip);
[OperationContract]
bool Logout(DeviceSession session);
[OperationContract]
bool IsLatestVersion(DeviceSession session, int version);
[OperationContract]
byte[] DownloadLatest(DeviceSession details);
[OperationContract]
DateTime GetServerTime(DeviceSession session, long branchID);
[OperationContract]
bool AddDevice(UserSession session, Device deviceitem);
[OperationContract]
bool RemoveDevice(UserSession session, long deviceID);
}
}
And the REST part:
namespace TSDEVICE.Rest
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class DeviceComponent
{
[WebInvoke(UriTemplate = "Login?deviceID={deviceID}&password={password}&serialNum={serialNum}", Method = "POST")]
[OperationContract]
public TMODELDEVICE.Entities.Session Login(string deviceID, string password, string serialNum)
{
string ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
TMODELDEVICE.Logic.DeviceComponent restDC = new TMODELDEVICE.Logic.DeviceComponent();
return restDC.Login(deviceID, password, serialNum, ip);
}
public string Sample()
{
return "Hello";
}
}
}
I have to access SOAP and REST, how can I do that? Thanks a lot!
EDIT
When I try to "Set as Start page" the .svc file, I get this error:
Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.
EDIT 2
Now I found out the real problem.
When ASP.NET compatibility mode in the web.config == true, SOAP fail to work, while REST requires it. What should I do with this? Thanks

I have a REST project that as both REST and SOAP service being exposed. Now I placed an .svc file for the SOAP service to be accessed by some clients.
The below screenshot gives the folder structure of my project, the route configuration in global.asax, Output accessing the Rest Service and accessing the .svc file (SOAP service)
UPDATE:
Please find my web.Config (My application is hosted on IIS):
Please find my class that implements my interface ISampleService:

While I appreciate the solutions listed above - I have a found it is far easier to manage/deploy if you don't over think the problem and follow a KISS principle.
Service Contract: IService.cs
namespace DontTazeMe.Bro
{
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet]
List<GeoMapData> GetToTheChopper();
}
}
Implementation: Service.cs
namespace DontTazeMe.Bro
{
public class WSDLService : IService
{
public List<GeoMapData> GetToTheChopper()
{
return ItsNotEasyBeingChessy.Instance.GetToTheChopperGeoData();
}
}
public class RESTService : WSDLService
{
// Let's move along folks, nothing to see here...
// Seriously though - there is no need to duplicate the effort made in
// the WSDLService class as it can be inherited and by proxy implementing
// the appropriate contract
}
}
Configuration
<system.serviceModel>
<services>
<!-- SOAP Service -->
<service name="DontTazeMe.Bro.WSDLService">
<endpoint address="" binding="basicHttpBinding" contract="DontTazeMe.Bro.IService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/DontTazeMe.Bro/Service/" />
</baseAddresses>
</host>
</service>
<service name="DontTazeMe.Bro.RESTService">
<endpoint address="" binding="webHttpBinding" contract="DontTazeMe.Bro.IService" behaviorConfiguration="Restful" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/DontTazeMe.Bro/Rest/Service/" />
</baseAddresses>
</host>
</service>
<behaviors>
<endpointBehaviors>
<behavior name="Restful">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
This method works just fine without getting carried away with configuration

Related

how to return JsonP from a WCP request?

I want to build a WCF service that will return a JsonP request. I want it to return the following,
jsonpCallback({"fileNames":"IDR023.T.201705201412.png, IDR023.T.201705201418.png"});
So I created the following WCF Service
IBOM.cs
[ServiceContract]
public interface IBOM
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json)]
string GetData();
}
BOM.cs
public class BOM : IBOM
{
public string GetData()
{
return "jsonpCallback({\"fileNames\":\"IDR023.T.201705201412.png, IDR023.T.201705201418.png\"});";
}
}
Webconfig
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="BomService.BOM" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="webHttpBinding" contract="BomService.IBOM" behaviorConfiguration="web">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
But I am getting back
"jsonpCallback({\"fileNames\":\"IDR023.T.201705201412.png, IDR023.T.201705201418.png\"});"
I am returning a string and trying to set it up to return what I need. Is this the best way for JSONP? or is there a better way to achieve what I need
Thanks
For anyone who is interested, I worked it out. Here is the code.
IBOM
[ServiceContract]
public interface IBOM
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json)]
Stream GetData();
}
BOM
public class BOM : IBOM
{
public Stream GetData()
{
string jsCode = "jsonpCallback" + "({\Test:\"" + fileNames + "\"});";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/javascript";
return new MemoryStream(Encoding.UTF8.GetBytes(jsCode));
}

Missing help description for task based WCF service

I'm currently hosting a few web services from within a WPF application. I also have enabled automatic help pages to simplify the service documentation. Every OperationContract is decorated with a Description attribute, containing information about the method.
However, whenever I take a look at my help pages, I realize that only methods with a return type of void will correctly display their Description attribute here. Methods returning Task or Task<t> will only say "Service at localhost:XXXXX/ServiceEndpoint".
As this pattern is used for IPC, I rely a lot on async operation contracts, so most of them will return a Task or Task<t>. Is there any way to fix this issue so the help gets displayed correctly?
namespace App
{
[ServiceContract]
public interface IMainService
{
[OperationContract]
[WebGet(UriTemplate = "visibility")]
[Description("Gets the main window visibility.")]
Task<bool> GetVisibilityAsync();
[OperationContract]
[WebInvoke(UriTemplate = "visibility", Method = "PUT")]
[Description("Sets the main window visibility.")]
Task SetVisibilityAsync(bool isVisible);
[OperationContract]
[WebInvoke(UriTemplate = "menu", Method = "PUT")]
[Description("Navigates to the main menu.")]
void NavigateToMainMenu();
[OperationContract]
[WebInvoke(UriTemplate = "shutdown", Method = "PUT")]
[Description("Requests the application to shutdown.")]
void RequestApplicationShutdown();
}
}
Here is my app.config
<system.web>
<compilation debug="false" targetFramework="4.5" />
</system.web>
<system.serviceModel>
<services>
<service name="App.MainService" behaviorConfiguration="rpcServiceBehavior">
<endpoint binding="webHttpBinding"
contract="App.IMainService"
behaviorConfiguration="webHttpBehavior"
name="RpcEndpoint"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:25565/main"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="rpcServiceBehavior" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Try to debug with another browser (or in incognito mode).
Explanation:
This is because you probably added a few descriptions, checked it on your browser. Then you added more description tags and checked it again on your browser which, instead of reloading the page, opened the one in cache. Browser will open page in browser in cache instead of reloading it when the page is static.

What requisities must WCF service have to be used as service/web reference?

I am learning WCF these days and probably don't know where to start. I want to create WCF REST Service, which will be accesible through HTTP requests (GET, PUT...). And at same time I want to be able to add this service as service reference or web reference and use them in the Web Application client as ordinary method. This issue is quite wide so I will by grateful for any hint or direction.
At this time, I have functional services and run them on my hosting. I can add Service Reference and Web Reference. Service reference is better for new code, as I reckognized, because it use WCF communication and thus it contains all former communication channels. When I add these references, I can use reference to GetSimpleDataService, but non of its methods. When I try to add these methods as reference, problem with metadata is noted.
WCF interface:
[ServiceContract]
public interface IGetSimpleDataService
{
[OperationContract]
[WebGet(UriTemplate = "User/{ID}")]
User GetUser(string ID);
[OperationContract]
[ScriptMethod(UseHttpGet = true)]
User GetUserByMethod(string ID);
[OperationContract]
[WebGet]
string ActivationTest();
[OperationContract]
[WebMethod]
string WebMethodTest();
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.serviceModel>
<services>
<service name="StoryHubWCFApp.TestStudentService" behaviorConfiguration="serviceBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="StoryHubWCFApp.ITestStudentService"
behaviorConfiguration="web"
/>
</service>
<service name="StoryHubWCFApp.GetSimpleDataService" behaviorConfiguration="serviceBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="StoryHubWCFApp.IGetSimpleDataService"
behaviorConfiguration="web"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Now I can get data via GET request, but I want to be able use service with Web/Service reference like this.:
string s = MyServices.ActivationTest();
I assume to use methods like this, which returns or takes values other than int and string I should have [DataContracts]? I understood too, I have to use [WebMethod] or [ScriptMethod], but I wasn't successful so far.
Thanks in regards for any correction.
You can so it almost as smoothly as your example shows...
Since your topic is quite broad I won't go in details just give pointers.
For your own classes, to be able to use them as parameters and/or return types. (in your case User) you have to define what and how to be serialized. You can read about that here:
https://msdn.microsoft.com/en-us/library/ms733127(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/ms733811(v=vs.110).aspx
Example:
[DataContract]
public class User
{
// This member is serialized.
[DataMember]
string FullName;
// This is not serialized because the DataMemberAttribute
// has not been applied.
private string MailingAddress;
}
Now you are able to use your class.
For calling the service:
You can add service reference: https://msdn.microsoft.com/en-us/library/bb386386.aspx (this would be a generated proxy to your service)
Or you can use ChannelFactory: https://msdn.microsoft.com/en-us/library/ms734681(v=vs.110).aspx
(with this you are in full control of the code, but might need to do more settings, i.e. endpoints.)

Adding WCF service reference in ASP.NET MVC app fails

I'm trying to add a WCF service to my ASP.NET MVC application. After setting it up, I get an error whenever I want to test it.
Here is my code:
BackgroundTask.svc
public class BackgroundTask : IBackgroundTask
{
public void ShutdownVm()
{
}
public void UpdateTable()
{
}
}
IBackgroundTask.cs
[ServiceContract]
public interface IBackgroundTask
{
[OperationContract]
void ShutdownVm();
[OperationContract]
void UpdateTable();
}
Web.config
<system.serviceModel>
<services>
<service behaviorConfiguration="bgtBehaviour" name="IsolutionsAzureManager.Controllers.BackgroundTask">
<endpoint address="BackgroundTask" binding="basicHttpBinding"
bindingConfiguration="" name="" contract="IsolutionsAzureManager.Controllers.IBackgroundTask" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:44304/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="bgtBehaviour">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
So, whenever I want to test my WFC service, I get this error:
Error: Cannot obtain Metadata from https://localhost:44304/Controllers/BackgroundTask.svc
Error: The HTML document does not contain Web service discovery information.
Can anyone see the mistake?
Because you are attempting to acquire the mex endpoint over Https, you'll also need to switch to mexHttpsBinding and
to enable the httpsGetEnabled setting:
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
Alternatively, obtain the endpoint via http (http://localhost:44304/Controllers/BackgroundTask.svc) and then just switch back to https once the client has built the service reference artifacts.

WCF + Xml-Rpc don't work

I have a classic WCF webservice. Few weeks ago, in order to answer to a client demand, I added Rest management to my webservice.
But, at the beginning of the week, another client said to me its system can only manage XML-RPC. So he needs to connect to my webservice via this protocol.
So I found this : Configuring XML-RPC behavior for IIS-hosted .SVC file?
First, I compiled the Microsoft.Samples.XmlRpc in order to add it to my project. Two Dll appears : Microsoft.Samples.XmlRpc & Microsoft.ServiceModel.XmlRpc
Then, I created a XmlRpcEndpointBehaviorExtension class, the same as the post above :
namespace WsZendesk
{
public class XmlRpcEndpointBehaviorExtension : BehaviorExtensionElement
{
protected override object CreateBehavior()
{
// this comes from Microsoft.Samples.XmlRpc
return new XmlRpcEndpointBehavior();
}
public override Type BehaviorType
{
get { return typeof(XmlRpcEndpointBehavior); }
}
}
}
After, I created my interface for Xml-Rpc :
namespace WsZendesk
{
[ServiceContract]
public interface IWsZendeskRpc
{
[OperationContract(Action = "wszendesk.GetUserIdFromBarcode")]
void GetUserIdFromBarcode(String sXmlIn, out String sXmlOut);
}
}
Finaly, I modified my web.config in order to allow RPC :
<system.serviceModel>
<services>
<service name="WsZendesk.WsZendesk" behaviorConfiguration="WsZendeskServiceBehavior">
<endpoint address="rest" behaviorConfiguration="restfulBehavior"
binding="webHttpBinding" bindingConfiguration="" name="RESTEndPoint"
contract="WsZendesk.IWsZendeskRest" />
<endpoint address="xmlrpc" behaviorConfiguration="xmlRpcBehavior"
binding="webHttpBinding" bindingConfiguration="" name="RPCEndPoint"
contract="WsZendesk.IWsZendeskRpc" />
<endpoint address="" behaviorConfiguration=""
binding="basicHttpBinding" bindingConfiguration="" name="SOAPEndPoint"
contract="WsZendesk.IWsZendesk" />
</service>
</services>
<extensions>
<behaviorExtensions>
<add name="xmlRpc"
type="WsZendesk.XmlRpcEndpointBehaviorElement, WsZendesk" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp />
</behavior>
<behavior name="xmlRpcBehavior">
<xmlRpc />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="WsZendeskServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Visual Studio said he don't know the child element 'xmlRpc'. So, when I try to launch my webservice, the same error appears during the execution.
Anybody can help me to use Xml-Rpc with my existing webservice ?
For information, my project is in C# 4.
It was not this:
<add name="xmlRpc"
type="WsZendesk.XmlRpcEndpointBehaviorElement, WsZendesk" />
But this:
<add name="xmlRpc"
type="WsZendesk.XmlRpcEndpointBehaviorExtension, WsZendesk" />

Categories