I have a WCF REST Service:
[ServiceContract]
public IService
{
[WebGet]
[OperationContract]
Data GetData(UserInfo userInfo);
}
UserInfo is a class:
public class UserInfo
{
public string UserName { get; set; }
public string Password { get; set; }
}
I want UserName and Password properties be filled from specific HTTP Headers but not from request body. How could I implement this?
WCF offers some extensibility points which could be helpful for this scenario. I suggest you should check IParameterInspector or IOperationInvoker. Both can work with input parameters. Then you will have to create IOperationBehavior as Attribute and mark your method with this attribute. But I expect this scenario will have one more bigger problem. You are using WebGet and complex type and you don't have any Uri template which will map to parameters - it is not possible. WebGet operations can use only parameters with basic types and when you create such parameter in operation it has to be mentioned in Uri template or exception is fired.
Related
I have a WCF Client, and the Endpoint has just been upgraded with a new method (OperationContract). I want to write a common method to handle the response from this new method as well as from the existing method at the endpoint.
I am trying to create a "Base" response class and adding common properties to it provided by the WCF endpoint, but I notice in my handler method, the properties are not being retained.
The code for the class I want all responses to inherit from looks like this :
public class ResponseBase
{
public string[] ItemsReturned;
public bool ItemsWereAvailable;
}
So I add partial declarations to get this onto the objects in the endpoint.
public partial class RetrieveResponse :ResponseBase
{
}
public partial class RetrieveResponse2 :ResponseBase
{
}
This way I have a handler method that just accepts "ResponseBase" as its input.
Am I doing this all wrong?
Any class whose instances will be return values and/or parameters of an operation contract should be decorated with the DataContract attribute, and the properties, as DataMembers:
[DataContract]
public class ResponseBase
{
[DataMember]
public string[] ItemsReturned { get; set; }
[DataMember]
public bool ItemsWereAvailable { get; set; }
}
http://msdn.microsoft.com/en-us/library/ms733127.aspx
If they are not, the DataContractSerializer doesn't serialize them.
I have a WCF operation contract which looks like this:
public void SavePersons(List<Person> list, bool IsSelected)
{
}
I am passing it a strongly typed list of Person objects (List<Person>) in my client. However, I am getting a bad request 400 message when calling the service. What am I doing wrong?
May I suggest you create you create a contract to encapsulate the parameters like so:
public void SavePersons(PersonCollectionContract Request)
{
...
}
[DataContract]
public class PersonCollectionContract
{
[DataContract]
public List<Person> People { get; set; }
[DataContract]
public bool IsSelected { get; set; }
}
[DataContract]
public class Person
{
...
}
I was facing a similar problem in passing a List<Health> of class Health type as a parameter to a wcf service method. I created a data contract in wcf service as below:
[DataContract]
public class Health
{
...
}
Defined a method in wcf service class such as:
public string GetData(List<Health> healthValues)
In my client application, while configuring/updating the service, I followed these steps:
Add/Update URL
Under Data Type (in Advanced), selected option, Collection type: System.Collection.Generic.List
And finally, I created a list and added the code in client as follows:
List<WcfService.Health> listHealth = new List<WcfService.Health>();
WcfService.Health h = new WcfService.Health();
.
.
listHealth.Add(h);
WcfService.Service1Client s = new WcfService.Service1Client();
string str = s.GetData(listHealth);
This solved my purpose and I was able to send the data as a list through wcf service.
I am programming a Azure WCF application.
A datacontract defined as below:
[DataContract]
public class UserInfo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int UserID { get; set; }
[DataMember]
public bool IsOnline { get; set; }
}
then I define a datacontract in my WCF service:
[DataContract(Name="UserInfo")]
public class ServiceUserInfo : UserInfo
{
[IgnoreDataMember]
public ICallback Callback { get; set; }
}
Then in the service contract, it will callback to client, the method as below
private void NoticeUsers(UserInfo currentuser)
{
var users = UserManager.GetAllActiveUsers();
foreach (var user in users)
{
if (user.UserName == currentuser.UserName)
continue;
user.Callback.UpdateUserList(currentuser);
}
}
Actually I pass a ServiceUserInfo object as parameter to the NoticeUsers method. Then an error will occurs as below:
There was an error while trying to serialize parameter http://tempuri.org/:user. The InnerException message was 'Type 'WCFServiceWebRole.ServiceUserInfo' with data contract name 'UserInfo:http://schemas.datacontract.org/2004/07/WCFServiceWebRole' 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.
I am not able to find solution for this issue.Please help.
I think I have found the root cause of the issue, however I do not know why.
The problem is caused by the Namespace attribute of the Service contract.
I didn't set the namespace of my service contract interface and data contract interface. I thought it would be set by default and it won't cause any problem. But actually the issue of this thread is caused by the Namespace attribute. I set a Namespace attribute for both service contract and data contract, of course the same namespace, then it worked. The problem never happens again.
However, I do not know why it caused this issue. If I do not set Namespace, it will be a default value of "http://tempuri.org", isn't it?
I have the following operation contract method:
[OperationContract]
MyOutputMessageType DeleteVRequest(DeleteVRequest type);
[MessageContract]
public class DeleteVRequest
{
[MessageHeader(Name = "UserId")]
public Guid UserId;
[MessageHeader(Name = "Password")]
public String Password;
[MessageHeader(Name = "Version")]
public String Version;
[MessageBodyMember]
public Guid Id;
}
[MessageContract]
public class MyOutputMessageType
{
[MessageBodyMember]
public string Response;
}
My question is how are the soap header values of the contract (userid,password,version) set for the call on the client side? If I write a header value using Add on the outgoingmessageheaders it does not seem to map to the value in the messagecontract. So for instance if I add a UserId value to the headers, it does not seem to see that within the DeleteVRequest method.
Thanks for any help, I've really been struggling with SOAP header reader/writing in SOAP.
If the client side is using .NET, the service proxy will take in a message contract rather than the data contract, and you can set the header properties as you would any other properties.
Otherwise, you can using the OperationContextScope to set header values manually:
using(OperationContextScope context = new OperationContextScope(proxy.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("HeaderName", "HeaderNamespace", "SomeValue"));
//Make your proxy calls here
}
I would like to create some sort of authentication attribute and attach it to various OperationContracts. Inside this attribute, it would check for an authentication token and make sure its still valid before the OperationContract is run.
What's the best way to implement this on the .net platform? Does wcf have any special attributes that already do this type of functionality? What I'm picturing is something similar to the attributes you can attach to MVC controllers that will perform operations before actions are run.
In case it's relevant, I am using WCF to create SOAP web services that will be consumed by clients on various platforms that support SOAP.. not just WCF clients
Here's some code to clarify what I'm trying to do:
interface:
[ServiceContract]
public interface IService
{
[OperationContract]
string ValidateUser(string username, string password);
[OperationContract]
string GetDataAndAuthInCode(string authtoken);
[MyAuthorizationAttribute]
[OperationContract]
string GetDataAndAuthWithAttribute(string authtoken);
}
implementation:
public class Service : IService
{
public string ValidateUser(string username, string password)
{
if (!Membership.ValidateUser(username, password))
throw new Exception("invalid user...");
else
return GenerateAuthToken(username);
}
public string GetDataAndAuthInCode(string authtoken)
{
if (!IsAuthTokenValid(authtoken))
throw new Exception("Auth token invalid expired");
else
return GetData();
}
public string GetDataAndAuthWithAttribute(string authtoken)
{
return GetData();
}
}
Looks like this is what I'm looking for.. "Custom Behaviors":
http://msdn.microsoft.com/en-us/magazine/cc163302.aspx#S7