I am writing a sample application using wcf rest for authentication. Here is the snapshot of the code:
service Interface:
[ServiceContract]
public interface IAuthenticate
{
[OperationContract]
[WebInvoke(BodyStyle=WebMessageBodyStyle.Bare,
Method = "POST", UriTemplate = "/VUser",RequestFormat= WebMessageFormat.Xml ), ]
string CreateUser(VUser user);
}
Datacontract class:
[DataContract]
public class VUser
{
public VUser()
{
}
[DataMember]
public string NickName { get; set; }
[DataMember]
public string lName { get; set; }
[DataMember]
public string fName { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public string PhoneNumber { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string Gender { get; set; }
[DataMember]
public int CountryCode { get; set; }
}
Service class:
public class Authenticate : IAuthenticate
{
#region IAuthenticate members
public string CreateUser(Vuser user)
{
//processing xml for response
}
#endregion IAuthenticate
}
client code:
Uri baseAddress = new Uri("http://localhost:8000");
using (WebServiceHost host = new WebServiceHost(typeof(Authenticate), baseAddress))
{
host.Open();
Console.WriteLine("Press any key to terminate");
Console.ReadLine();
host.Close();
}
Now I am using fiddler to send the request after host.open() and send the the request has shown:
post http://localhost:8000/Vuser/
User-Agent: Fiddler
Host: localhost:8000
content-length: 233
content-type: text/xml
and in request body :
sandy
r
sunil
sunil.r
919900101948
winter
male
01
but it is returning me HTTP/1.1 400 Bad Request. My question is am I passing the vuser class correctly to the create user method or is there any other way to send the vuser.
Please help me.
It could be a problem with serialization.
Serialization uses the default consrtuctor, without parameters.
In C# the compiler will automatically create a default constructor, except if you create a constructor with a parameter.
The Authenticate class is missing a default constructor, you will therefore have probelms sending it over WCF.
Kindly specify The Datacontract Namespace in DataContract Class
[DataContract(Namespace = "http://xxx.xxx.xxx/Service.svc")]
and follow same in Xml file
The Namespace in both client and server should match. Try to add namespace name as
[DataContract(Namespace = "http://sample.com")]
public class VUser
in the server contract. And then make sure the xml string has the xmlns value with the same namespace
"<VUser xmlns=\"http://sample.com" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">...</VUser>"
Related
I am developing a Wcf Restful Service which contains data contract "User" shown below
[DataContract]
public class User
{
public User()
{
}
[DataMember(Name = "Name")]
public string Name { get; set; }
[DataMember(Name = "Mobile")]
public string Mobile { get; set; }
[DataMember(Name = "Email")]
public string Email { get; set; }
[DataMember(Name = "IsImageUpdated")]
public bool IsImageUpdated { get; set; }
}
Now i would like to add one mode data member of type Image,When i try to add Image with type Stream it showing exception
[DataMember(Name = "Iamge")]
public Stream Image { get; set; }
"The InnerException message was 'Type 'System.IO.FileStream' with data contract name 'FileStream:http://schemas.datacontract.org/2004/07/System.IO' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details."
The service i am developing having many Data contract's,I read some posts which saying the issue can be resolved by changing the Datacontract to message contract,Does a service supports different contract types(like Data,Message).
i need a solution.
This is not possible when using a WebHttpBinding.
Combining streamed and buffered Content is only possible when the binding has a SOAP message Format and you use MessageContract instead of DataContract.
Using a byte[] or returning the stream directly is supported.
[DataMember(Name = "Iamge")]
public byte[] Image { get; set; }
or
[OperationContract]
[WebGet(UriTemplate = "/Image")]
Stream GetImage();
or when using NetTcpBinding, WsHttpBinding, BasicHttpBinding, ...
[MessageContract]
public class ImageData
{
[MessageBodyMember]
public Stream Image { get; set; }
[MessageHeader]
public string Name { get; set; }
}
Im trying to use a Class in a WCF service. When im calling the
u.attributeChanges.Add(a);
i get:
"Object reference not set to an instance of an object"
If create the classes in the client application it's working.
UpdateChanges Class
[DataContract]
public class UpdateChanges
{
private void Initialize()
{
this.attributeChanges = new List<AttributeChanges>();
}
public UpdateChanges()
{
this.Initialize();
}
[DataMember]
public string objectGuid { get; set; }
[DataMember]
public Utilities.ObjectTypes objectType { get; set; }
[DataMember]
public Utilities.ChangeType changeType{ get; set; }
[DataMember]
public List<AttributeChanges> attributeChanges { get; set; }
[OnDeserializing]
public void OnDeserializing(StreamingContext ctx)
{
this.Initialize();
}
}
AttributeChanges class
[DataContract]
public class AttributeChanges
{
[DataMember]
public string attributeName { get; set; }
[DataMember]
public string attributeValue { get; set; }
}
Client Code:
Service.DirsyncServiceClient proxyClient;
proxyClient = Utilities.GetProxy("http://192.168.1.45/vDir/Service.svc");
Service.UpdateChanges u = new Service.UpdateChanges();
Service.AttributeChanges a = new Service.AttributeChanges();
a.attributeName = "Attribute1";
a.attributeValue = "Value1";
u.attributeChanges.Add(a);
proxyClient.SaveObject(u);
Anyonw know how to solve this?
You're using a generated client code.
The problem is that the client generates this code on base of the WSDL xlm. The code in the CTOR doesn't generated in the client because the client can't be aware of this code.
You have a few options-
1. Use a shared DLL with the data contract instead of generating it via a web reference.
2. Implement it yourself in a 'partial' class.
I'm building some services which have a common header. This header has a certain layout in the request, and a different one in the response (i.e., there are two classes).
However, when I add a reference or use svcutil, the proxy is generated with the same header in both request and response types.
For instance:
[MessageContract]
class Contract<THeader, TBody>
{
[MessageHeader] public THeader Header { get; set; }
[MessageBodyMember] public TBody Body { get; set; }
}
class MyRequestHeader
{
public string RequestorId { get; set; }
}
class MyResponseHeader
{
public string ErrorMessage { get; set; }
}
The OperationContract is something like:
[OperationContract]
public Contract<MyResponseHeader, ResponseBody> Process(Contract<MyRequestHeader, RequestBody> data);
The proxy becomes something like:
var client = new ...;
var header = new MyRequestHeader();
var body = new RequestBody();
**ResponseBody**
response = client.Process(ref header, body);
As you can see, the header (Request) is passed as ref; That probably means WCF is having this header as the same in request and response. And the MyResponseHeader disappears.
Anyone can shed some light on the subject?
There is something strange going on here.
I tried to reproduce your problem, and got the following results (i had to mark some types public, and added [DataContract] to your header classes).
Here is a view of the WSDL:
The generated code (svcutil 4.0.30319.18046) uses MyRequestHeader in the Response message as well:
This is caused by the following XSD:
As you can see there is only one instance generated for the "Header" class.
I tried creating types for the generic classes, as follows:
[MessageContract]
public abstract class Contract<THeader, TBody>
{
[MessageHeader]
public THeader Header { get; set; }
[MessageBodyMember]
public TBody Body { get; set; }
}
[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
public string RequestorId { get; set; }
}
[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
public string ErrorMessage { get; set; }
}
[MessageContract]
public class RequestContract : Contract<MyRequestHeader, string>
{ }
[MessageContract]
public class ResponseContract : Contract<MyResponseHeader, string>
{ }
[ServiceContract]
public interface IService1
{
[OperationContract]
ResponseContract Process(RequestContract data);
}
But that did not fix the problem, the generated client ResponseContract still is generated using a Header of type RequestHeader.
Even changing the service code to use two diffrent message contracts:
[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
public string RequestorId { get; set; }
}
[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
public string ErrorMessage { get; set; }
}
[MessageContract]
public class RequestContract<TBody>
{
[MessageHeader]
public MyRequestHeader Header { get; set; }
[MessageBodyMember]
public TBody Body { get; set; }
}
[MessageContract]
public class ResponseContract<TBody>
{
[MessageHeader]
public MyResponseHeader Header { get; set; }
[MessageBodyMember]
public TBody Body { get; set; }
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ResponseContract<string> Process(RequestContract<string> data);
}
does not solve the problem:
Even removing all shared inheritance and generics as follows:
[DataContract(Name="RequestHeader")]
public class MyRequestHeader
{
public string RequestorId { get; set; }
}
[DataContract(Name = "ResponseHeader")]
public class MyResponseHeader
{
public string ErrorMessage { get; set; }
}
[MessageContract(WrapperName="RequestMessage")]
public class RequestContract
{
[MessageHeader]
public MyRequestHeader Header { get; set; }
[MessageBodyMember]
public string Body { get; set; }
}
[MessageContract(WrapperName = "ResponseMessage")]
public class ResponseContract
{
[MessageHeader]
public MyResponseHeader Header { get; set; }
[MessageBodyMember]
public string Body { get; set; }
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ResponseContract Process(RequestContract data);
}
still results in the RequestHeader being used in the ResponseMessage.
I think the answer lies somewhere in this documentation:
WSDL Considerations
When generating a Web Services Description
Language (WSDL) contract from a service that uses message contracts,
it is important to remember that not all message contract features are
reflected in the resulting WSDL [sic]. Consider the following points: WSDL
cannot express the concept of an array of headers. When creating
messages with an array of headers using the
MessageHeaderArrayAttribute, the resulting WSDL reflects only one
header instead of the array.
The resulting WSDL document may not reflect some protection-level
information.
The message type generated in the WSDL has the same name as the class
name of the message contract type.
When using the same message contract in multiple operations, multiple
message types are generated in the WSDL document. The names are made
unique by adding the numbers "2", "3", and so on, for subsequent uses.
When importing back the WSDL, multiple message contract types are
created and are identical except for their names.
I have a XML structure like this:
<Message>
<Messagehead>
<OSType>Android</OSType>
<RouteDest>SiteServerName</RouteDest>
<ActionType>Enroll</ActionType>
</Messagehead>
<MessageBody>
<Raw>
<![CDATA[OrienginalMessageContent]]>
</Raw>
</MessageBody>
</Message>
and I want upload this XML to WCF 4.0 my rest service:
public string Enroll(Message instance)
{
// TODO: Add the new instance of SampleItem to the collection
return "success";
}
the Message is a DataContract type, I setup it like below:
[DataContract(Namespace = "")]
public class Message
{
[DataMember]
public MessageHead MessageHead { get; set; }
[DataMember]
public MessageBody MessageBody { get; set; }
}
public class MessageHead
{
public OSType OSType { get; set; }
public string RouteDest { get; set; }
public Action Action { get; set; }
}
public class MessageBody
{
public string RawRequestContent { get; set; }
}
but when I get the Message instance from the server side, all the property is null, except the OSType, can anybody tell me why? How could I solve this problem?
Besides being a really bad name for a class (since it's already used in the WCF runtime), your Message class also has some flaws:
<Message>
<Messagehead>
....
</Messagehead>
Your <Messagehead> has a lower-case h in the middle - yet your class defines it to be upper case:
[DataContract(Namespace = "")]
public class Message
{
[DataMember]
public MessageHead MessageHead { get; set; }
This will not work - case is important and relevant in a WCF message! If your XML has a lower-case h, so must your DataContract class!
Your XML also requires a <Raw> tag inside your <MessageBody>
<MessageBody>
<Raw>
<![CDATA[OriginalMessageContent]]>
</Raw>
</MessageBody>
yet your data contract doesn't respect that:
public class MessageBody
{
public string RawRequestContent { get; set; }
}
Again - those don't line up! Names are important - and they must match between your XML representation of the message, and the C# class representing that message.....
I try to submit a request to a REST API using WCF; here's what I've done:
namespace Sample
{
[ServiceContract]
[XmlSerializerFormat]
public interface ISampleApi
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "users.xml", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)]
User CreateUser(User user);
}
}
And this is my User Class:
namespace Sample.Entity
{
[XmlRoot("user")]
public class User
{
[XmlElement("company")]
public string Company { get; set; }
[XmlElement("country-code")]
public string ContryCode { get; set; }
[XmlElement("created-at")]
public DateTime CreatedAt { get; set; }
[XmlElement("email")]
public string Email { get; set; }
[XmlElement("external-identifier")]
public string ExternalIdentifier { get; set; }
[XmlElement("id")]
public int Id { get; set; }
[XmlElement("measurement-system")]
public string MeasurmentSystem { get; set; }
[XmlElement("profile")]
public string Profile { get; set; }
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("username")]
public string Username { get; set; }
[XmlElement("account-type")]
public string AccountType { get; set; }
}
}
But when I call CreateUser method and pass a User object to it I receive this error message:
The remote server returned an error: (422) Unprocessable Entity.
Any idea what causes this?
That exception means that the web server responded with an error code, namely 422. You will need to check with the administrator of the remote site, why that might be. (Or look at the body of the response if any was returned, it might include some hints).
Here is the explanation of error code 422: https://www.rfc-editor.org/rfc/rfc4918#section-11.2
The request you are sending to the server is most likely invalid in some way or another. What the exact error might be, is impossible to tell without knowing which request you are sending against which system.
This error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous XML instructions
Re-check the users.xml for instructions
country-code is string or integer value?