I have a very simple [OperationContract] called TestClass that gets called like this:
var person = { "Name": "Dave", "City":"HB", "State": "CA", "Zip":"92649" };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(person),
url: "MyService.svc/TestClass",
success: function (data) {
$("#output").text("[ " + data + "]");
}
});
What I'm not understanding, and can't seem to find, is the preferred way of using these services. I've been searching everywhere for the past few days and I feel really overwhelmed with what I've found so far. I read one post where somebody said not to use Message but to create their own DataContract which I tried.
Here is my Operation Contract:
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public Message TestClass(Message m)
{ return WebOperationContext.Current.CreateTextResponse(JsonConvert.SerializeObject("Ok"));}
Besides having 4 input values to TestClass, I would prefer just one. Message is the only thing that seems to work. I tried using just a string and that value is always null.
I've tried creating a [DataContract] for the data and use that as the parameter in the TestClass call but that also is null.
I'm new to using these service types so any pointers for a beginner is greatly appreciated.
Thank you in advance.
UPDATE
IService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfTest
{
[System.ServiceModel.ServiceContractAttribute()]
public interface IService
{
[System.ServiceModel.Web.WebInvokeAttribute(BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Bare,
RequestFormat = System.ServiceModel.Web.WebMessageFormat.Json,
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json)]
[System.ServiceModel.OperationContractAttribute()]
void ProcessData(RootClass input);
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class RootClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name;
[System.Runtime.Serialization.DataMemberAttribute()]
public string City;
[System.Runtime.Serialization.DataMemberAttribute()]
public string State;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Zip;
}
}
ServiceZ.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Newtonsoft.Json;
namespace WcfTest
{
public class ServiceZ : IService
{
public void ProcessData(RootClass input)
{
int i = 6; // used for a breakpoint
}
}
}
Index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="Scripts/json2.js" type="text/javascript"></script>
<script type="text/javascript">
$().ready(function () {
var person = { "Name": "Dave", "City": "HB", "State": "CA", "Zip": "92649" };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(person),
url: "ServiceZ.svc/ProcessData",
success: function (data) {
$("#output").text("OK!");
},
error: function (jqXHR, textStatus, errorThrown) {
debugger;
}
});
});
</script>
</head>
<body>
<div id="output" style="background: lightgreen;">--></div>
</body>
You can use a the data contract for your data. The tool at http://carlosfigueira.me/JsonUtilities/JsonToContract.htm (more information about it at http://blogs.msdn.com/b/carlosfigueira/archive/2011/01/11/inferring-schemas-for-json.aspx) can give you a data contract which is compatible with the JSON data. By running it with your input I got the code below.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:v4.0.30319
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[System.ServiceModel.ServiceContractAttribute()]
public interface IService
{
[System.ServiceModel.Web.WebInvokeAttribute(BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Bare, RequestFormat = System.ServiceModel.Web.WebMessageFormat.Json, ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json)]
[System.ServiceModel.OperationContractAttribute()]
void ProcessData(RootClass input);
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class RootClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name;
[System.Runtime.Serialization.DataMemberAttribute()]
public string City;
[System.Runtime.Serialization.DataMemberAttribute()]
public string State;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Zip;
}
Update: I created a new project (empty web application), and added the following files - the client received the correct response. Try comparing with what you have to see if there is anything different. And the 415 error you're getting usually indicates which you don't have the appropriate binding / behavior on this endpoint. To enable REST endpoints (which can accept JSON), the endpoint needs to have the webHttpBinding and a behavior with the <webHttp/> on it. Or another alternative (which is what I used) is to use the WebServiceHostFactory on the .svc file, in which case you don't need anything on web.config.
ServiceZ.svc
<%# ServiceHost Language="C#" Debug="true"
Service="StackOverflow_7141298.ServiceZ"
CodeBehind="ServiceZ.svc.cs"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
IServiceZ.cs
namespace StackOverflow_7141298
{
[System.ServiceModel.ServiceContractAttribute()]
public interface IService
{
[System.ServiceModel.Web.WebInvokeAttribute(BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Bare, RequestFormat = System.ServiceModel.Web.WebMessageFormat.Json, ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json)]
[System.ServiceModel.OperationContractAttribute()]
string ProcessData(RootClass input);
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class RootClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name;
[System.Runtime.Serialization.DataMemberAttribute()]
public string City;
[System.Runtime.Serialization.DataMemberAttribute()]
public string State;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Zip;
}
}
ServiceZ.svc.cs
namespace StackOverflow_7141298
{
public class ServiceZ : IService
{
public string ProcessData(RootClass input)
{
if (input == null) return "NULL!!!";
StringBuilder sb = new StringBuilder();
return string.Format("Name={0},City={1},State={2},Zip={3}",
input.Name ?? "<<null>>",
input.City ?? "<<null>>",
input.State ?? "<<null>>",
input.Zip ?? "<<null>>");
}
}
}
HTMLPage1.htm
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="json2.js"></script>
<script type="text/javascript">
$().ready(function () {
var person = { "Name": "Dave", "City": "HB", "State": "CA", "Zip": "92649" };
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(person),
url: "ServiceZ.svc/ProcessData",
success: function (data) {
$("#output").text(data);
},
error: function (jqXHR, textStatus, errorThrown) {
//debugger;
$("#output").text("Error!");
}
});
});
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>
Related
I have define my routeconfig as :
routes.MapRoute(
"addcomments",
"addcomments/{urlLanguage}",
new { controller = "Home", action = "addcomments", urlLanguage = "h" }
);
and in Homecontroller :
public ActionResult addcomments(string urlLanguage)
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public string addcommentssave(int id, string yourName, string youremail, string website, string yourComment)
{
string message = " Thanks for sharing your comment! If your comment doesn't appear right away, please be patient as it may take a few minutes to publish or may require moderation.";
DateTime WishDateTime = DateTime.UtcNow;
string szRemoteAddr = System.Web.HttpContext.Current.Request.UserHostAddress;
Comments commit = new Comments();
commit.comdate = WishDateTime;
commit.comments = yourComment;
commit.email = youremail;
commit.Name = yourName;
commit.Website = website;
commit.IpAddress = szRemoteAddr;
commit.PostId = id;
commit.IsVisible = 0;
_session.Comment.Add(commit);
_session.SaveChanges();
//ViewBag.result= "<div class='message success'>" + message + "</div>";
// return View();
return "<div class='message success'>" + message + "</div>";
}
in addcomments view
#using (Ajax.BeginForm("addcommentssave", "home", null,
new AjaxOptions {
HttpMethod = "POST",
UpdateTargetId = "commentmessage",
OnBegin = "wait()",
OnSuccess = "success()",
LoadingElementId = "updating" },
new { id = "_commitForm" }))
{
}
but when i run it my form action become empty like
form action="" ....`
how to i solve it, help me
I created a simple test site to try and see if I could replicate your issue.
Here is my route config:
namespace Comments
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Use LocalDB for Entity Framework by default
Database.DefaultConnectionFactory = new SqlConnectionFactory(#"Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=True");
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
}
Here is my HomeController.cs:
namespace Comments.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return RedirectToAction("AddComment");
}
[HttpGet]
public ActionResult AddComment()
{
return View();
}
[HttpPost]
public ActionResult AddComment(int id, string yourName, string youremail, string website, string yourComment)
{
return Content(String.Format("Got a comment, id = {0}, yourName = {1}, youremail = {2}, website = {3}, yourComment = {4}",
id,
yourName,
youremail,
website,
yourComment));
}
}
}
Here is my AddComment.cshtml:
#{
ViewBag.Title = "Add Comment";
}
<h2>Add Comment</h2>
#using (Ajax.BeginForm("AddComment", "Home", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "commentmessage", OnBegin = "wait()", OnSuccess = "success()", LoadingElementId = "updating" }, new { id = "_commitForm" }))
{
<b>Form Here</b>
}
Here is the view source:
<DOCTYPE html>
<html>
<head>
<title>Add Comment</title>
<link href="/Content/Site.css" rel="stylesheet" type="text/css" />
<script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>
<body>
<h2>Add Comment</h2>
<form action="/Home/AddComment" data-ajax="true" data-ajax-begin="wait()" data-ajax-loading="#updating" data-ajax-method="POST" data-ajax-mode="replace" data-ajax-success="success()" data-ajax-update="#commentmessage" id="_commitForm" method="post"> <b>Form Here</b>
</form>
</body>
</html>
So you can see the form path rendering. Try simplifying your route config (I didn't do anything special).
I've looked at the many similar issues posted but couldn't find a solution that worked for me. So the call to Get is working fine but call to POST returns 404. I created a simple WebAPI project (MVC 4).
public class CasesController : ApiController
{
[Inject]
public ICaseManager CaseManager { get; set; }
// GET api/cases
public IEnumerable<Case> Get()
{
return CaseManager.ListCases();
}
// POST api/cases
[HttpPost]
public void Post([FromBody]Case objCase)
{
}
}
So when I navigate to http://localhost:34645/api/cases I get the following:
[{"CaseID":1,"CaseCode":"one","CaseDescription":"case one"},{"CaseID":2,"CaseCode":"two","CaseDescription":"case two"}]
I created another project (ASP.Net) and have an html file within it with the following code:
<script src="Scripts/jquery-2.0.3.js"></script>
<script src="Scripts/jquery-2.0.3.intellisense.js"></script>
<script type="text/javascript">
function postData() {
$.post('http://localhost:34645/api/cases', { "CaseID": 3, "CaseCode": "three", "CaseDescription": "case three" }).done(function (data) { alert("Success " + data); }).fail(function (xhr, textStatus, errorThrown) { alert("Error " + xhr.status); });
}
</script>
Every time I click the button that invokes postData, I get an alert "Error 404".
Here are my routes:
Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
WebAPIConfig.Register:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//RA: to get JSON
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
}
RouteConfig:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Please advise.
Be careful about the order of the WebApi registration line. I found when I specifically had the Global.asax.cs code in this order it worked:
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Otherwise, it failed with 404 error.
If these are two separate solutions, check they're both running - it's possible that they're trying to share a server instance, so the WebAPI you're trying to hit isn't running when the other app is. If they're projects within the same solution, check that they're both set to run on startup, or again, the WebAPI won't be running when the ASP.NET project tries to access it.
Try below. It works for me. I have removed some properties for brevity.
public class CasesController : ApiController {
// GET api/cases
public IEnumerable<Case> Get() {
var caseManager = new CaseManager();
return caseManager.ListCases();
}
// POST api/cases
[HttpPost]
public string Post([FromBody]Case objCase) {
return objCase.CaseName;
}
}
public interface ICaseManager {
IEnumerable<Case> ListCases();
}
public class CaseManager {
public IEnumerable<Case> ListCases()
{
return new List<Case>() { new Case() { CaseID = 1, CaseName = "one" } };
}
}
public class Case {
public int CaseID { get; set; }
public string CaseName { get; set; }
}
View
<script type="text/javascript">
//function postData() {
// $.post('http://localhost:58820/api/cases', { "CaseID": 3, "CaseCode": "three", "CaseDescription": "case three" })
// .done(function (data) { alert("Success " + data); }).fail(function (xhr, textStatus, errorThrown)
// { alert("Error " + xhr.status); });
//}
$(document).ready(function () {
$('#save-source').click(function (e) {
e.preventDefault();
var source = {
'ID': 0,
'CaseID': 3,
'CaseName': "three",
};
$.ajax({
type: "POST",
dataType: "json",
url: "/api/cases",
data: source,
success: function (data) {
alert(data);
},
error: function (error) {
jsonValue = jQuery.parseJSON(error.responseText);
}
});
});
});
</script>
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myForm"}))
{
<input type="submit" id="save-source" name="save-source" value="Add" />
}
After different attempts, this article helped me the most:
WebAPI and CORS enabled REST services
I also installed the Ninject WebApi DependencyResolver package through NuGet.
You write that you post to $.post('http://localhost:34645/api/cases'...
Either you change the url to include the action method name explicitly, like: $.post('http://localhost:34645/api/cases/post'..
or you add in your config.Routes.MapHttpRoute a default action which will be used when none action specified in the url
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action="Post", id = RouteParameter.Optional }
);
OR you can change your route to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
);
(without {action} and then web api will reach the Post method when you use a post http verb (it knows to do it automatically, but if you set a default action it'll override it)
I have a Jquery Ajax call more or like below
$.ajax(url, {
type: httpMethod,
contentType: "application/json; charset=utf-8",
data: '{name:"abc",age:23,address:"29 judd ce"}',
The web api action is
public HttpResponseMessage Post([FromBody] FormDataCollection data)
{
However the parameter 'data' is always null.
Is this a web api limitation or am i doing it the wrong way
Thanks
Use a view model instead:
public class UserViewModel
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
that your controller action will take:
public HttpResponseMessage Post(UserViewModel model)
{
...
}
it's possible
$.ajax("http://localhost:57281/api/Values", {
type: "POST",
data: '{name:"abc",age:23,address:"29 judd ce"}',
contentType: "application/x-www-form-urlencoded"
});
//POST api/values
public void Post([FromBody]FormDataCollection value)
{
}
Also works without [FromBody]
But you will get only ONE pair of key/value
Better use something like that
$.ajax("http://localhost:57281/api/Values", {
type: "POST",
data: 'name=abc&age=23&address=29 judd ce',
contentType: "application/x-www-form-urlencoded"
});
& is used as a separator for each pair
I want to invoke a WCF service using JSONP. There are two methods,
1. "Hello" method, it does not take any paramter. This works fine
2. "Hello1" methods takes a string paramter. This does not work properly. It should return the value which I am passing.
Following is the code snippet
Server code
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace WcfService1
{
[ServiceContract(Namespace = "JsonpAjaxService")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string Hello()
{
return "I got the call";
}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string Hello1(string str)
{
return "Hi, you passed me " + str;
}
}
}
Web config code
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="None" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint name="" crossDomainScriptAccessEnabled="true"/>
</webScriptEndpoint>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="True"
automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>
Client code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="JS/JQuery.js" type="text/javascript"></script>
<script type="text/javascript">
var Type;
var Url;
var Data;
var ContentType;
var DataType;
var ProcessData;
var method;
//Generic function to call WCF Service
function CallService() {
$.ajax({
type: Type, //GET or POST or PUT or DELETE verb
url: Url, // Location of the service
data: Data, //Data sent to server
contentType: ContentType, // content type sent to server
dataType: DataType, //Expected data format from server
processdata: ProcessData, //True or False
success: function (msg) {//On Successfull service call
ServiceSucceeded(msg);
},
error: ServiceFailed// When Service call fails
});
}
function ServiceFailed(result) {
alert('test');
alert('Service call failed: ' + result.status + '' + result.statusText);
Type = null;
Url = null;
Data = null;
ContentType = null;
DataType = null;
ProcessData = null;
}
function Hello() {
var uesrid = "1";
Type = "GET";
Url = "http://localhost:52136/Service1.svc/Hello";
DataType = "jsonp"; ProcessData = false;
method = "Hello";
//debugger;
CallService();
}
function Hello1() {
debugger;
var uesrid = "1";
Type = "GET";
ContentType = "application/json; charset=utf-8";
Url = "http://localhost:52136/Service1.svc/Hello1";
DataType = "jsonp"; //ProcessData = false;
method = "Hello1";
Data = "{'str':'abc'}"; //"{'Input':'a123'}";//"{'StringValue':'1234'}";
//debugger;
CallService();
}
function ServiceSucceeded(result) {
debugger;
if (DataType == "jsonp") {
alert(result); /* Problem, While calling 'Hello1' method I do not get the value in the return string*/
}
}
function ServiceFailed(xhr) {
alert(xhr.responseText);
if (xhr.responseText) {
var err = xhr.responseText;
if (err)
error(err);
else
error({ Message: "Unknown server error." })
}
return;
}
$(document).ready(
function () {
try {
//Hello();
Hello1();
} catch (exception) { }
}
);
</script>
</head>
<body>
<form id="form1" runat="server">
<h1>
JSONP Service Client Page</h1>
</form>
</body>
</html>
Can anybody tell me what is wrong in the code while calling Hello1 method
Atul Sureka
Try passing the data as an object, not as a string:
function Hello1() {
debugger;
var uesrid = "1";
Type = "GET";
ContentType = "application/json; charset=utf-8";
Url = "http://localhost:52136/Service1.svc/Hello1";
DataType = "jsonp"; //ProcessData = false;
method = "Hello1";
Data = {str : 'abc'};
//debugger;
CallService();
}
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace WcfService1
{
[ServiceContract(Namespace = "JsonpAjaxService")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string Hello()
{
return "I got the call";
}
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "SetQuoteEntities?str={str}")]
public string Hello1(string str)
{
return "Hi, you passed me " + str;
}
}
}
When I modified attribute webGet it worked for me.
We have custom XML serialization for our "protocol" here:
[XmlRoot("axf", Namespace = Axf10Namespace)]
public class AxfDocument : IXmlSerializable
{
public const string Axf10Namespace = "http://schemas.***.ru/axf/axf-1.0.0";
// ...
}
and all's fine when using standard .NET XmlSerializer:
<?xml version="1.0" encoding="utf-16"?>
<axf version="1.0.0" createdAt="2011-10-20T13:11:40" xmlns="http://schemas.***.ru/axf/axf-1.0.0">
<itineraries>
<!-- -->
</itineraries>
</axf>
Now that we try to use this class in a bare-bones WCF service:
[OperationContract]
AxfDocument GetItineraries(ItinerariesQuery query);
actual XML document that gets sent to client side is this:
<GetItinerariesResult version="1.0.0" createdAt="2011-10-20T13:17:50" xmlns="http://tempuri.org/">
<itineraries xmlns="http://schemas.***.ru/axf/axf-1.0.0">
<!-- rest is fine, serialization code does work -->
How do I bend WCF to send root element as-is and not to replace it with its own?
By default, the operation responses are wrapped in the operation name. You can, however, use a MessageContract in the operation definition to use an "unwrapped" response, as shown below. If you look at the response body of the request in Fiddler, you'll see that it's exactly as the one from the serialization.
public class StackOverflow_7836645
{
[XmlRoot("axf", Namespace = Axf10Namespace)]
public class AxfDocument : IXmlSerializable
{
public const string Axf10Namespace = "http://schemas.something.ru/axf/axf-1.0.0";
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
}
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("intineraries", Axf10Namespace);
writer.WriteElementString("item", Axf10Namespace, "one value");
writer.WriteElementString("item", Axf10Namespace, "another value");
writer.WriteEndElement();
}
}
[MessageContract(IsWrapped = false)]
public class OperationResponse
{
[MessageBodyMember(Name = "axf", Namespace = AxfDocument.Axf10Namespace)]
public AxfDocument axf;
}
[ServiceContract]
public interface ITest
{
[OperationContract]
OperationResponse GetAxf();
}
public class Service : ITest
{
public OperationResponse GetAxf()
{
return new OperationResponse { axf = new AxfDocument() };
}
}
public static void Test()
{
Console.WriteLine("Serialization");
MemoryStream ms = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(AxfDocument));
xs.Serialize(ms, new AxfDocument());
Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
Console.WriteLine();
Console.WriteLine("Service");
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.GetAxf());
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}