WCF REST service not returning DataContract object - wcf

I have a simple WCF service defined by the following ServiceContract:
[ServiceContract]
public interface IInventoryService
{
[OperationContract]
Item GetItemFromBarcode(string barcode);
[OperationContract]
string Test(string testString);
}
With Item defined like this:
[DataContract]
public class Item
{
[DataMember]
public virtual int Id { get; set; }
<Snip>
}
And the actual service implemented thusly:
public class InventoryService : IInventoryService
{
[WebGet(UriTemplate = "/Barcode/{barcode}/Item", ResponseFormat = WebMessageFormat.Json)]
public Item GetItemFromBarcode(string barcode)
{
var item = (from b in repository.Query<ItemBarcode>()
where b.BarcodeData == barcode
select b.Item).FirstOrDefault();
return item;
}
[WebGet(UriTemplate = "/Test/{testString}",ResponseFormat=WebMessageFormat.Xml)]
public string Test(string testString)
{
return testString;
}
}
With the following in the app.config for the program hosting the service:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="RESTFriendly">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="InventoryService">
<endpoint address="/Inventory" behaviorConfiguration="RESTFriendly" binding="webHttpBinding" contract="IInventoryService"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Now that the code dump is out of the way, the issue: I can invoke the Test method just fine with curl or Fiddler, it returns a serialized string. However, invoking the method that returns an object returns nothing. Curl spits back curl: (56) Failure when receiving data from the peer and Fiddler responds ReadResponse() failed: The server did not return a response for this request.
From what I read, this should Just Work (tm). Is there something obvious I'm missing?

So, it seems you can't have DataMember of an interface type, like the IList<ItemBarcode>. There go my hopes of using my NHibernate model objects as DTOs.

Related

WCF Rest service not working

ILeaveManagement class
[ServiceContract]
public interface ILeaveManagement
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "get")]
List<ServiceReference1.LeaveRequest> GetLeaveDetails();
}
LeaveManagement class
public class LeaveManagement : ILeaveManagement
{
public List<ServiceReference1.LeaveRequest> GetLeaveDetails()
{
try
{
var entities = new ServiceReference1.leaverequest_Entities(new Uri(serviceUrl));
var result = entities.LeaveRequestCollection;
return result.ToList();
}
catch
{
return new List<ServiceReference1.LeaveRequest>();
}
}
}
configuration
<service behaviorConfiguration="DRLExternalList.LeaveManagementBehavior" name="DRLExternalList.LeaveManagement">
<endpoint address="" binding="wsHttpBinding" contract="DRLExternalList.ILeaveManagement"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<behavior name="DRLExternalList.LeaveManagementBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
I have deployed the project in IIS 7.5. When i run the application , it is saying BadRequest.
I have verrified in fiddler. i saw 400 error.
Please help me on this.
Try using webHttpBinding in your endpoint instead of the wsHttpBinding, or add it as an additional one and change the address. I use a bindingNamespace in my project, but I don't think you need it.
<endpoint address="XMLService"
binding="webHttpBinding"
behaviorConfiguration="restXMLBehavior"
contract="DRLExternalList.ILeaveManagement">
</endpoint>
Add an Endpoint Behavior
<endpointBehaviors>
<!-- Behavior for the REST endpoint -->
<behavior name="restXMLBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
I also annotate the OperationContract slightly differently, but it shouldn't make all that much of a difference. I'll give it to you just in case...
[WebGet(UriTemplate = "/GetLeaveDetails", ResponseFormat = WebMessageFormat.Xml)]
To call the service, it would look like this using the XMLService endpoint name:
http://myWebHost.com/WebService/MyService.svc/XMLService/GetLeaveDetails
Hosting an wcf service into a website issue : System.ArgumentException: ServiceHost only supports class service types
the above link helped me to solve my issue.
<%# ServiceHost Language="C#" Debug="true" Service="restleave.ProductRESTService" %>

404 Error when trying to execute web service

I have a simple web service I have created. I'm using Visual Studio 2012 .NET 4.5.
Here is the service contract:
using System.Runtime.Serialization;
using System.ServiceModel;
namespace GEMS.Core.WCFService
{
[ServiceContract]
public interface IMenuService
{
[OperationContract]
void AddMenuItem(string menuId, string parentId, string title, string description, string url);
[OperationContract]
void UpdateMenuItem(string menuId, string parentId, string title, string description, string url);
[OperationContract]
void DeleteMenuItem(string menuId);
[OperationContract]
MenuEntry[] GetAllMenuItems();
}
[DataContract]
public class MenuEntry
{
[DataMember]
public string MenuId { get; internal set; }
[DataMember]
public string ParentId { get; internal set; }
[DataMember]
public string Title { get; internal set; }
[DataMember]
public string Description { get; internal set; }
[DataMember]
public string Url { get; internal set; }
}
}
The relevant portion of the app.config is:
<system.serviceModel>
<services>
<service name="GEMS.Core.WCFService.MenuService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8020/GEMS.Core.WCFService/MenuService/" />
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="GEMS.Core.WCFService.IMenuService" >
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I publish it to my IIS server (local to my box).
In the client app, I create a service reference. When I click Discover, it finds:
http://localhost:8020/GEMS.Core.WCFService/MenuService/mex
When I run my client, however, I get the following message:
There was no endpoint listening at:
http://localhost:8020/GEMS.Core.WCFService/MenuService/ that could
accept the message. This is often caused by an incorrect address or
SOAP action. See InnerException, if present, for more details.
The inner exception merely says that it got a 404 error from the web server.
The client's .config file has the following auto-generated xml:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMenuService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8020/GEMS.Core.WCFService/MenuService/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMenuService"
contract="WCF_MenuService.IMenuService" name="BasicHttpBinding_IMenuService" />
</client>
</system.serviceModel>
I've been going around in circles for hours and can't figure out what I've got glitched up, but surely I've done somethign wrong.
Not sure that it matters, but the client is an ASP.NET MVC app.
As Pete explained Newtonsoft.json.dll causes client to not generate the service code. You can either delete the dll and then add the service reference again.
Or you can do try following solution that worked for me. When you add a service reference,
Click on the 'Advanced...' button in the 'Add service reference' - window
Disable 'Reuse types in referenced assemblies'.
Then your classes should be generated.

Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata.?

trying to build a RestFull service with wcf running in the WcfTestClient.exe. The problem is that I get an error:
Failed to add a service. Service metadata may not be accessible.
I added a mex endpoint in the config file but does not solve it:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="MyRest.Service" behaviorConfiguration="ServBehave">
<!--Endpoint for REST-->
<endpoint
address="XMLService"
binding="webHttpBinding"
behaviorConfiguration="restPoxBehavior"
contract="MyRest.IService"/>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServBehave" >
<!-- 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 for the REST endpoint for Help enability-->
<behavior name="restPoxBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(UriTemplate = "/Employees", ResponseFormat = WebMessageFormat.Xml)]
Employee[] GetEmployees();
}
[DataContract]
public class Employee
{
[DataMember]
public int EmpNo { get; set; }
[DataMember]
public string EmpName { get; set; }
[DataMember]
public string DeptName { get; set; }
}
Service1.cs
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class Service1 : IService1
{
public Employee[] GetEmployees()
{
return new Employee[]
{
new Employee() {EmpNo=101,EmpName="Mahesh",DeptName="CTD"},
new Employee() {EmpNo=102,EmpName="Akash",DeptName="HRD"}
};
}
}
With WCF Restful service, do you actually need meta-data to expose service or to work on it? The answer is "NO". It's against the principles of Rest. Meta-data represents the interface(the operations), and for REST interface is fixed(http methods). WcfTestClient is for testing SOAP based Service(as they have to expose their interface through mex bindings).
Testing a RESTFUL service for http get could be vary easy. you just have to invoke it from your browser, using the URL. To test other http methods, you have to build your custom client.
If this seems a big task, then you could also use tools like Fiddler to build request data. An example could be seen here

how to log JSON response in WCF at service level

I have a WCF service that returns JSON to the clients.
This is the app.config
<system.serviceModel>
<services>
<service name="MyServices.MyService">
<endpoint address="" behaviorConfiguration="JsonBehavior" binding="webHttpBinding"
contract="Myervices.IMyervice">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/MyEmulator/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="JsonBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
This is a sample opertaion exposed by the service
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, Method = "GET", UriTemplate = "me/{id}")]
JsonObject GetObject(string id, string connection_type);
Now, I would like to log every request that the service receives from clients and response that is being sent back to clients...in this case it sin JSOn.
I have create a custom MessageInspector as follows
public class MyMessageInspector : IDispatchMessageInspector
{
private bool LoggingEnabled;
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
Guid correlationState = Guid.NewGuid();
if (this.LoggingEnabled)
{
StringBuilder message = new StringBuilder();
message.AppendFormat("CorrelationState = {0}{1}", correlationState, Environment.NewLine);
message.AppendFormat("Local Address = {0}{1}", channel.LocalAddress, Environment.NewLine);
message.AppendFormat("Remote Address = {0}{1}", channel.RemoteAddress, Environment.NewLine);
message.AppendLine("Request");
message.AppendLine(request.ToString());
message.AppendLine();
this.logger.LogMessage(message.ToString());
}
return correlationState;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
if (this.LoggingEnabled)
{
StringBuilder message = new StringBuilder();
message.AppendFormat("CorrelationState = {0}{1}", correlationState, Environment.NewLine);
message.AppendLine("Reply");
message.AppendLine(reply.ToString());
message.AppendLine();
this.logger.LogMessage(message.ToString());
}
}
#endregion
}
But this doesnt seem to log any of the resposne.. the response.Tostring() only says "...stream"
the Above works if my service returns data in SOAP XML format..but i want it to log JSON response which is the text inside the *.js file downloaded in the browser when i call the REST service endpoint. ex: http://localhost:8080/MyService/me/2/
any ideas how I can achieve this?
This code provides a mechanism for working with REST messages, and as a bonus allows SOAP to pass through as normal. It's a little intrusive (the stream is destroyed by reading so the code needs to regenerate it) but I haven't found any better way.
http://code.msdn.microsoft.com/WCF-REST-Message-Inspector-c4b6790b

Trying to get basic Http URL with querystring parameters processed in WCF service

I'm trying to process a post by a third party server (Paypal) processed by my server through a WCF (.Net 3.5 SP1) service. All I need is to get and process the values with the query string. This sounds incredibly easy, but after a weekend, I'm still stumped. Any help would be greatly appreciated.
Passing the following URL from my browser to the service causes a AddressFilter mismatch fault (below).
http://localhost:9409/PPInfo.svc/ReadResponse?RESULT=0&AUTHCODE=10001&RESPMSG=APROVED&PNREF=12345
produces
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
- <Code>
<Value>Sender</Value>
- <Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:DestinationUnreachable</Value>
</Subcode>
</Code>
- <Reason>
<Text xml:lang="en-US">The message with To 'http://localhost:9409/PPInfo.svc/ReadResponse?RESULT=0&AUTHCODE=10001&RESPMSG=APROVED&PNREF=12345' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.</Text>
</Reason>
</Fault>
// web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ASEEESPrivate.PPInfoBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ASEEESPrivate.PPInfoBehavior" name="ASEEESPrivate.PPInfo">
<endpoint address="" binding="webHttpBinding" contract="ASEEESPrivate.IPPInfo">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
================================
[ServiceContract]
public interface IPPInfo
{
// expecting RESULT = 0 and RESPMSG = APPROVED
[OperationContract]
[WebGet(UriTemplate = "Presponse?RESULT={result}&AUTHCODE={authcode}&RESPMSG={respmsg}&AVSDATA={avsdata}&PNREF={pnref}",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml)]
void ReadResponse();
}
=========================================
// write parameters of query string to tlkpOnlineMessage table
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, AddressFilterMode=AddressFilterMode.Any)]
public class PPInfo : IPPInfo
{
public void ReadResponse()
{
var qString = HttpContext.Current.Request.QueryString;
var ctx =
new MembershipEntities();
var log = new tlkpOnlineMessage();
foreach (string s in qString)
{
log.LoginPageMsg = s;
ctx.AddTotlkpOnlineMessages(log);
}
ctx.SaveChanges();
}
}
Besides the typo in your code, I believe you have two problems that are easily correctable:
1) For a RESTful service, you should define an endpoint behavior and enable the webHttp behavior. You can do this by adding an <endpointBehavior> to your web.config as such:
<behaviors>
<serviceBehaviors>
<behavior name="ASEEESPrivate.PPInfoBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="ASEEESPrivate.PPInfoEndpointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
And then add this endpoint behavior to your service definition:
<service behaviorConfiguration="ASEEESPrivate.PPInfoBehavior" name="WcfRestService1.PPInfo">
<endpoint address="" binding="webHttpBinding" contract="WcfRestService1.IPPInfo"
behaviorConfiguration="ASEEESPrivate.PPInfoEndpointBehavior">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
2) Secondly, you define a UriTemplate for your service with placeholders (result, authcode, etc.) but you don't define parameters for them in your interface. If you're going to define a UriTemplate for your service definition with placeholders, then you need to have your service define those parameters accordingly. You can do that as such:
[ServiceContract]
public interface IPPInfo
{
// expecting RESULT = 0 and RESPMSG = APPROVED
[OperationContract]
[WebGet(UriTemplate = "ReadResponse?RESULT={result}&AUTHCODE={authcode}&RESPMSG={respmsg}&AVSDATA={avsdata}&PNREF={pnref}",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml)]
void ReadResponse(string result, string authcode, string respmsg, string avsdata, string pnref);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, AddressFilterMode = AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PPInfo : IPPInfo
{
public void ReadResponse(string result, string authcode, string respmsg, string avsdata, string pnref)
{
...
}
}
By using a UriTemplate, you don't need to extract your querystring parameters out; or, if you want to extract parameters from your querystring, don't define a UriTemplate.
Once I made these two changes, I was able to get the service to run locally on my machine.
I hope this helps!