WCF JSON implementation - json

I'm trying to implement a very simple WCF service that returns JSON. I'm trying for 6 hours now and it still doesn't work. I hope you can help me out with this.
Person
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace Tcf.AtX.Services
{
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
}
}
Service Contract
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Tcf.AtX.Services
{
[ServiceContract]
public interface IBroadcastService
{
/// <summary>
/// Broadcasts the specified message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
[OperationContract]
[WebInvoke(Method="GET", ResponseFormat= WebMessageFormat.Json)]
Person Broadcast(string message);
}
}
Service Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tcf.AtX.Broadcasting;
namespace Tcf.AtX.Services
{
public class BroadcastService : IBroadcastService
{
/// <summary>
/// Broadcasts the specified message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
public Person Broadcast(string message)
{
return new Person() { Name = message };
}
}
}
Configuration
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true"/>
</system.web>
<system.serviceModel>
<services>
<service name="Tcf.AtX.Services.BroadcastService">
<endpoint address="" binding="webHttpBinding" contract="Tcf.AtX.Services.IBroadcastService" behaviorConfiguration="json"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/Tcf.AtX.Services/BroadcastService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="json">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
The problem is that i don't see the service inside the test client, so i can't test my method.
I also wrote a test client myself, but i can't create an instance of my service when i reference it to my project.
Can someone please explain to me what i'm doing wrong?
Best regards,
Rob

The test client doesn't work for non-SOAP endpoints (i.e., the one you have, which uses the WebHttpBinding). Try simply creating a program that tries to call the operation you have, something like the code below
WebClient c = new WebClient();
Console.WriteLine(
c.DownloadString(
"http://localhost:8732/Design_Time_Addresses/Tcf.AtX.Services/Broadcast?message=MyMessage"));
One more thing, you'll need to change the [WebInvoke(Method="GET")] attribute to [WebGet].

Related

WCF REST service streaming JSON objects

I need a windows service in which the REST API dumps a bunch of JSON objects into a stream (content-type: application/stream+json).
Example response (not array of objects):
{ id: 1, name: "name 1" }
{ id: 2, name: "name 2" }
{ id: 3, name: "name 3" }
{ id: 4, name: "name 4" }
It is possible doing this in WCF REST? Or maybe I should try something other?
After a few days I found a solution of my case. First I was modify App.config file and add binding configuration to the endpoint that allow streamed response. Next, operation of service contract must have return Stream. Then in implementation of service contract I set outgoing response content type to "application/stream+json", serialize all objects using DataContractJsonSerializer and write to MemoryStream. At the end I was set position of MemoryStream to zero and then return that stream.
Sample code bellow.
App.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<service name="WinService.WcfService">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBindingStreamedResponse" contract="WinService.IWcfService" behaviorConfiguration="webHttp" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingStreamedResponse" transferMode="StreamedResponse" maxReceivedMessageSize="67108864"/>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="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>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
ServiceContract:
[ServiceContract]
public interface IWcfService
{
[OperationContract]
[WebGet(UriTemplate = "/stream/{param}", ResponseFormat = WebMessageFormat.Json)]
Stream GetJsonStreamedObjects(string param);
}
Implementation of ServiceContract:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WcfService : IWcfService
{
public Stream GetJsonStreamedObjects(string param)
{
var stream = new MemoryStream();
var serializer = new DataContractJsonSerializer(typeof(JsonObjectDataContract));
WebOperationContext.Current.OutgoingResponse.ContentType = "application/stream+json";
foreach (JsonObjectDataContract jsonObjectDataContract in Repository.GetJsonObjectDataContracts(param))
{
serializer.WriteObject(stream, jsonObjectDataContract);
}
stream.Position = 0;
return stream;
}
}

WCF rest service for list - json not working

My wcf reset service has only 2 contracts, one is working always and the other did not work.
Service Code:
Public Class BasicServ
Implements IBasicServ
Public Function DoWork() Implements IBasicServ.DoWork
Return "Working"
End Function
Function Authorize(ByVal id As String, ByVal pw As String) Implements IBasicServ.Authorize
Dim c As New List(Of Guid)
For i = 0 To 10
c.Add(Guid.NewGuid)
Next
Return c
'Return Guid.NewGuid
End Function
End Class
Contract File code:
<ServiceContract()>
Public Interface IBasicServ
<OperationContract()>
<WebGet(UriTemplate:="test/", BodyStyle:=WebMessageBodyStyle.Wrapped, RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)>
Function DoWork()
<OperationContract()>
<WebGet(UriTemplate:="Authorize/{id}/{pw}", BodyStyle:=WebMessageBodyStyle.Wrapped, RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)>
Function Authorize(ByVal id As String, ByVal pw As String)
End Interface
Web Config File:
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messagelistener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="d:\logs\myMessages.svclog"></add>
</listeners>
</source>
</sources>
<trace autoflush="true"/>
</system.diagnostics>
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true"
logMessagesAtServiceLevel="false"
logMessagesAtTransportLevel="false"
logMalformedMessages="true"
maxMessagesToLog="5000"
maxSizeOfMessageToLog="2000">
</messageLogging>
</diagnostics>
<services>
<service behaviorConfiguration="ServBehav" name="AssistantWcf.BasicServ">
<endpoint address="auth" behaviorConfiguration="EndBehav" binding="webHttpBinding" name="endpointname" contract="AssistantWcf.IBasicServ" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="EndBehav">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServBehav">
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpGetBinding="webHttpBinding" httpGetBindingConfiguration="" />
<!-- 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>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
While debugging/testing, I found that, if I return only 1 GUID in Authoriza method, it is working, but when I am sending a list of GUID, it is not working, and the SVClog file is not getting created. Could you please help me understand WCF REST service better. Thank you.
From above comments and few experiments, the solution for the question is that a return type is not compulsory if it is string, but if anything else, return type must be specified. Better if return type is provided always.

Endpoint not found WCF

I have WCF library that I hosted , the login function work well, but the second function ReturnCounter
the interface is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace PMAService
{
[ServiceContract]
public interface IPMA
{
[OperationContract]
string Login(string username, string password);
[OperationContract]
List<usp_ReturnEncounter_Result> ReturnEncounter();
}
}
and the code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Web;
using System.Security.Cryptography;
using System.Web.Security;
namespace PMAService
{
public class PMA : IPMA
{
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "LogIn/{username}/{password}")]
public string Login(string username, string password)
{
if (Membership.ValidateUser(username, password))
return "true";
else
return "false";
}
// Method to retrieve the Counter
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "ReturnEncounter")]
public List<usp_ReturnEncounter_Result> ReturnEncounter()
{
using (PMAEntities context = new PMAEntities())
{
return context.usp_ReturnEncounter().ToList();
}
}
}
}
where I connect to Entity framework
the web.config look like
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<roleManager enabled="true" />
<membership>
<providers>
<remove name="AspNetSqlMembershipProvider"/>
<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="Login"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="1"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
passwordStrengthRegularExpression="" />
</providers>
</membership>
<authentication mode="Windows"/>
<customErrors mode="On"/>
</system.web>
<system.serviceModel>
<services>
<service name="PMAService.PMA">
<endpoint binding="webHttpBinding" contract="PMAService.IPMA" behaviorConfiguration="web">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
the login/x/y work well, while ReturnCounter give the error endpoint not found
any idea to fix that please
First of all enable Tracing on your Service and see what is the cause for exception.
Also you would consider increasing ReaderQuotas on your server and client side so that larger data is passed without any problem. Sample shown below:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>  
 
Also i see in your code that you are passing the object fetched by entity framework directly. There are situations where the entity framework objects dont get deserialzed and might cause exception. Create a simple POCO and then populate the fetched data and return the POCO.
Why WebInvoke?
For use of a Get operation you need to use WebGet for this Method.
WebInvoke is for just Executing Insert Update Delete uperations.
We use POST, PUT and DELETE method names for them.(Orderly)
When you need to get some data you should do something like that,
[WebGet(UriTemplate = "ReturnEncounter",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
As you notice there is a request format this may be XML or JSON enumed on WebMessageFormat.
For post ops. you may use WebRequest object.
Hope helps.

WCF Json GET Service: Check that the sender and receiver's EndpointAddresses agree

I've been working in .NET for a while now, but I'm new to WCF. I'm trying to create my very first WCF service using JSON. I thought I would start really, really simple and then build from there. But I have somehow managed to screw up even the most simple of services. Here's what I've got so far.
Web.Config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="MarathonInfo.MarathonInfoService">
<endpoint address="http://localhost:10298/MarathonInfoService.svc" binding="webHttpBinding" contract="MarathonInfo.IMarathonInfo" />
</service>
</services>
<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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Then, in the service file:
namespace MarathonInfo
{
public class MarathonInfoService : IMarathonInfo
{
public String GetData()
{
return "Hello World";
}
}
}
And in the interface:
namespace MarathonInfo
{
[ServiceContract]
public interface IMarathonInfo
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/GetData", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
String GetData();
}
}
So, when I go to this url:
http://localhost:10298/MarathonInfoService.svc/GetData
I get this error:
The message with To
'http://localhost:10298/MarathonInfoService.svc/GetData' cannot be
processed at the receiver, due to an AddressFilter mismatch at the
EndpointDispatcher. Check that the sender and receiver's
EndpointAddresses agree.
I am able to execute the service just fine through Visual Studio in debug mode. But in the browser, I only get that error.
What am I doing wrong?
Thanks!
Casey
If you want to create a WCF WebHTTP Endpoint (i.e., one which returns JSON, and uses the [WebGet] / [WebInvoke] attributes), the endpoint needs to have the <webHttp/> behavior associated with it.
<system.serviceModel>
<services>
<service name="MarathonInfo.MarathonInfoService">
<endpoint address="http://localhost:10298/MarathonInfoService.svc"
binding="webHttpBinding"
contract="MarathonInfo.IMarathonInfo"
behaviorConfiguration="Web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
</system.serviceModel>

WCF service to accept a post encoded multipart/form-data

Does anyone know, or better yet have an example, of a WCF service that will accept a form post encoded multipart/form-data ie. a file upload from a web page?
I have come up empty on google.
Ta, Ant
So, here goes...
Create your service contract which an operation which accepts a stream for its only parameter, decorate with WebInvoke as below
[ServiceContract]
public interface IService1 {
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/Upload")]
void Upload(Stream data);
}
Create the class...
public class Service1 : IService1 {
public void Upload(Stream data) {
// Get header info from WebOperationContext.Current.IncomingRequest.Headers
// open and decode the multipart data, save to the desired place
}
And the config, to accept streamed data, and the maximum size
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebConfiguration"
maxBufferSize="65536"
maxReceivedMessageSize="2000000000"
transferMode="Streamed">
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Sandbox.WCFUpload.Web.Service1Behavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Sandbox.WCFUpload.Web.Service1" behaviorConfiguration="Sandbox.WCFUpload.Web.Service1Behavior">
<endpoint
address=""
binding="webHttpBinding"
behaviorConfiguration="WebBehavior"
bindingConfiguration="WebConfiguration"
contract="Sandbox.WCFUpload.Web.IService1" />
</service>
</services>
</system.serviceModel>
Also in the System.Web increase the amount of data allowed in System.Web
<system.web>
<otherStuff>...</otherStuff>
<httpRuntime maxRequestLength="2000000"/>
</system.web>
This is just the basics, but allows for the addition of a Progress method to show an ajax progress bar and you may want to add some security.
I don't exactly know what you're trying to accomplish here, but there's no built-in support in "classic" SOAP-based WCF to capture and handle form post data. You'll have to do that yourself.
On the other hand, if you're talking about REST-based WCF with the webHttpBinding, you could certainly have a service methods that is decorated with the [WebInvoke()] attribute which would be called with a HTTP POST method.
[WebInvoke(Method="POST", UriTemplate="....")]
public string PostHandler(int value)
The URI template would define the URI to use where the HTTP POST should go. You'd have to hook that up to your ASP.NET form (or whatever you're using to actually do the post).
For a great introduction to REST style WCF, check out Aaron Skonnard's screen cast series on the WCF REST Starter Kit and how to use it.
Marc