I am proper struggling getting that "magic" moment when WCF is configured nicely and jQuery is structuring its requests/understanding responses nicely.
I have a service:
<%# ServiceHost Language="C#" Debug="true" Service="xxx.yyy.WCF.Data.ClientBroker" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>
This was recommended by the man Rick Strahl to avoid having to define the behaviours within Web.config.
My interface for the WCF service sits in another assembly:
namespace xxx.yyy.WCF.Data
{
[ServiceContract(Namespace = "yyyWCF")]
public interface IClientBroker
{
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
IClient GetClientJson(int clientId);
}
}
The concrete service class is:
namespace xxx.yyy.WCF.Data
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
class ClientBroker : IClientBroker
{
public IClient GetClientJson(int clientId)
{
IClient client=new Client();
// gets and returns an IClient
return client;
}
}
}
My IClient is an Entity Framework class so is decorated with DataContract/DataMember attributes appropriately.
I am trying to call my WCF service using the methods outlined on Rick Strahl's blog at http://www.west-wind.com/weblog/posts/324917.aspx (the "full fat" version). The debugger jumps into the WCF service fine (so my jQuery/JSON is being understood) and gets the IClient and returns it. However, when I return the response, I get various useless errors. The errors I am getting back don't mean much.
I am using POST.
Am I right to be using an Interface instead of a concrete object? As it does get into the WCF service, it does seem to be the encoding of the result that is failing.
Does anyone have any ideas?
At first glance there are three problems with your code:
1: you should use the ServiceKnownTypeAttribute to specify known types when exposing only base types in your operation contracts:
[ServiceContract(Namespace = "yyyWCF")]
public interface IClientBroker
{
[OperationContract]
[ServiceKnownType(typeof(Client))]
[WebInvoke(
Method="GET",
BodyStyle=WebMessageBodyStyle.WrappedRequest,
ResponseFormat=WebMessageFormat.Json)]
IClient GetClientJson(int clientId);
}
2: You should use WebMessageBodyStyle.WrappedRequest instead of WebMessageBodyStyle.Wrapped because the latter is not compatible with WebScriptServiceHostFactory.
3: IMHO using Method="GET" would be more RESTful for a method called GetClientJson than Method="POST"
Another advice I could give you when working with WCF services is to use SvcTraceViewer.exe bundled with Visual Studio. It is a great tool for debugging purposes. All you need is to add the following section to your app/web.config:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "WcfDetailTrace.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
Then invoke the web method and WcfDetailTrace.e2e file will be generated in your web site root directory. Next open this file with SvcTraceViewer.exe and you will see lots of useful information. For example it could say:
Cannot serialize parameter of type
'MyNamespace.Client' (for operation
'GetClientJson', contract
'IClientBroker') because it is not the
exact type 'MyNamespace.IClient' in
the method signature and is not in the
known types collection. In order to
serialize the parameter, add the type
to the known types collection for the
operation using
ServiceKnownTypeAttribute.
Of course you should not forget commenting this section before going into production or you might end up with some pretty big files.
I am 99% sure you cant return an interface. I dont think Interfaces are serializable.
check out this thread
Related to the question, a while ago I posted an article on my blog showing all the steps needed to get a WCF service working together with jQuery code on the client side:
http://yoavniran.wordpress.com/2009/08/02/creating-a-webservice-proxy-with-jquery/
Related
I am looking for some advice on how I can do a piece of work I have. Basically I have multiple webservice that takes the same methods and parameters. And it is a pain to always have to get proxy classes, and change the code when a new provider is accepted and I am looking at ways to be able to add the webservice URL in my config and at runtime, be able to compile generate proxy classes and communicate with the remote machine dynamically.
As an example: I have to send data to a method Called UpdateCustomers (int id, string name,string surname,DateTime DateofBirth) to a provider and if We decide to use provider A be able to change the webservice url in config to point to A, or when we decide to change to B etc...
The webservices are .asmx or .svc
I am looking for hint and advice.
Regards
Sounds like a job for WCF Routing.
Depending on how you want to route your calls, you can define message filters which you can use to evaluate if incoming calls fulfil a set of criteria, for example, that a certain value in the soap payload is set to a specific value:
<filters>
<filter name="myXPathFilter1"
filterType="XPath"
filterData="//valueIWantToFilterOn = somevalue"/>
</filters>
You can then register the filter to map to a specific endpoint:
<filterTables>
<table name="myRoutingTable">
<filters>
<add filterName="myXPathFilter1" endpointName="UpdateCustomers1" />
<add filterName="myXPathFilter2" endpointName="UpdateCustomers2" />
...
</filters>
</table>
</filterTables>
Hi it might be a duplicate but writing here since i was unable to fix the issue from the posts i have seen so far.
I am having DataContracts in my WCF services and on my client I want to consume my services as DataContract objects only, but when i am creating a Service reference my WCF services generating the message contracts for all the methods.
[ServiceContract]
public interface IUserService
{
[OperationContract]
UserVO GetUser(int Id);
}
[DataContract]
public Class UserVO
{
[DataMember]
public int Id{get;set;};
}
I have un-checked the "Always generate message contracts" and checked reuse types in referenced libraries where entities are available(Data Contract).
My reference.cs is having a message contract like
System.ServiceModel.MessageContractAttribute(WrapperName="GetUser", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
public partial class GetUserRequest {
}
EDIT 1:
my Reference.svcmap has client configuration like this
<ClientOptions>
<GenerateAsynchronousMethods>false</GenerateAsynchronousMethods>
<EnableDataBinding>true</EnableDataBinding>
<ExcludedTypes />
<ImportXmlTypes>false</ImportXmlTypes>
<GenerateInternalTypes>false</GenerateInternalTypes>
<GenerateMessageContracts>false</GenerateMessageContracts>
<NamespaceMappings />
<CollectionMappings>
<CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
</CollectionMappings>
<GenerateSerializableTypes>true</GenerateSerializableTypes>
<Serializer>Auto</Serializer>
<UseSerializerForFaults>true</UseSerializerForFaults>
<ReferenceAllAssemblies>true</ReferenceAllAssemblies>
<ReferencedAssemblies />
<ReferencedDataContractTypes />
<ServiceContractMappings />
EDIT 2:
I am trying to achieve something like below
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IUserService/GetUserDetails", ReplyAction="http://tempuri.org/IUserService/GetUserDetailsResponse")]
[System.ServiceModel.FaultContractAttribute(typeof(UserServiceFaultContract), Action="http://tempuri.org/IUserService/GetUserDetailsUserServiceFaultContractFault", Name="UserServiceFaultContract", Namespace="http://schemas.datacontract.org/2004/07/mynamespace")]
MyEntities.UserVO GetUserDetails(int id);
By default, WCF uses the DataContractSerializer class to serialize data types. If your scenario requires the use of the XmlSerializer, instead, then you can manually switch to the XmlSerializer by applying the XmlSerializerFormatAttribute attribute to your service
The following MSDN article describes the process:
https://msdn.microsoft.com/en-us/library/ms733901(v=vs.110).aspx
Recommend careful consideration of the security notes before switching serialization classes.
Then share the assembly with the client! Put the service interface and all the DataContracts in one assembly. Then the client can use the channel channelfactory "pattern" to connect to the WCF service.
I'm trying create a ASMX webservice that can perform a HTTP GET request. I have the following simple snippet of code to illustrate what I've already done.
using System.Web.Script.Services;
...
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HelloWorld(HttpContext context)
{
return context.Request.Params.Get("userId").ToString();
}
In addition to this, I've also added the following nodes in my Web.config file
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
The problem that I'm facing is that I'm constantly getting the dreaded "System.Web.HttpContext cannot be serialized because it does not have a parameterless constructor" error message whenever I try to debug this webservice. I have no idea what the problem is, and I would really appreciate any assistance that is offered to get me out of this quandary. I realize that HTTP GET requests are supposed to be very simple, but I'm really uncertain of what the cause of my frustrations are.
I think you want
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HelloWorld(int userId)
{
return userId.ToString();
}
You can specify parameters in the function signature and you can access the HttpContext as Context (a property on the base class WebService) if you need it.
I have a web application that accesses a database through a wcf service. The idea is to abstract the data from the web application using the wcf service. All that works fine but I am also using the built in roleprovider using the SqlRoleManager which does access the aspnetdb database directly. I would like to abstract the roleprovider by creating a custom roleprovider in a wcf service and then accessing it through the wcf service.
I have created the custom role provider and it works fine but now I need to place it in a wcf service.
So before I jump headlong into trying to get this to work through the WCF service, I created a second class in the web application that accessed the roleprovider class and changed my web config roleprovider parameters to use that class. So my roleprovider class is called, "UcfCstRoleProvider" and my web.config looks like this:
<roleManager
enabled="true"
defaultProvider="UcfCstRoleProvider">
<providers>
<add
name="UcfCstRoleProvider"
type="Ucf.Security.Wcf.WebTests.UcfCstRoleProvider, Ucf.Security.Wcf.WebTests"
connectionStringName="SqlRoleManagerConnection"
applicationName="SMTP" />
</providers>
</roleManager>
My class starts like this:
public class UcfCstRoleProvider : RoleProvider
{
private readonly WindowsTokenRoleProvider _roleProxy = new WindowsTokenRoleProvider();
public override string ApplicationName
{
get
{
return _roleProxy.ApplicationName;
}
set
{
_roleProxy.ApplicationName = value;
}
}
As I said, this works fine. So the second class is called BlRoleProvider that has identical properties and parameters as the roleprovide but does not implement RoleProvider. I changed the web.config to point to this class like this:
<roleManager
enabled="true"
defaultProvider="BlRoleProvider">
<providers>
<add
name="UcfCstRoleProvider"
type="Ucf.Security.Wcf.WebTests.BlRoleProvider, Ucf.Security.Wcf.WebTests"
connectionStringName="SqlRoleManagerConnection"
applicationName="SMTP" />
</providers>
</roleManager>
But I get this error.
"Provider must implement the class 'System.Web.Security.RoleProvider'."
I hope I have explained well enough to show what I am trying to do. If I can get the roleprovider to work through another class in the same application, I am sure it will work through the WCF service but how do I get past this error?
Or maybe I took a wrong turn and there is a better way to do what I want to do??
I think your best bet is to create a custom role provider and implement each method. In the implementation of each method, call the WCF service to do the data access. Eg:
public class WcfRoleProvider: RoleProvider
{
public bool IsUserInRole(string username, roleName)
{
bool result = false;
using(WcfRoleService roleService = new WcfRoleService())
{
result = roleService.IsUserInRole(username, roleName);
}
return result;
}
}
No, you have to have a class that must implement RoleProvider. That will not work. If you can't have this class inherit from RoleProvider directly, consider creating a RoleProvider wrapper class that implements RoleProvider's props/methods, but utilizes whatever you need to do with this second class.
This error isn't specific to WCF, but is specific to the role provider framework.
HTH.
Looking at your code it appears that you already have your configuration using a custom role provider.
If you want to be able to authentiacate users mking calls through your web service you should implement a custom header that authenticates each request against your configured role provider.
Things work slightly differently in WCF, it's not like you have access to session and application states since each call is considered to be a stateless one, a custom header however will offset that by handling this stuff as the call is made.
I would like to make a RESTful app of HTTPhandlers without having to define every endpoint by making an entry in the web.config, i'd like the style of attaching attributes to a class constructor eg:
public class obj : IHttpHandler
{
[WebGet(UriTemplate = "/accounts/{id}")]
public obj(string id)
{
// this is just an eg, it worild normally include caching and
// a template system
String html = File.ReadAllText("/accounts/accounts.htm");
html.replace("id", id);
httpcontext.current.response.write(html)
}
}
instead of
<httpHandlers>
<clear />
<add verb="GET" path="/accounts/*" type="MyApp.obj" />
</httphandlers>
The way i'm doing it now i have 100's of endpoints in the web.config :( i'd rather define them in the class. And i don't want to make extra files (.asmx) either. I'd like an app of just .htm files with tokens and .cs files
Thanks!
You could automate the registration of the endpoints and so on, with a custom ServiceHost, which overrides the ApplyConfiguration() method, which then virtualizes the configuration so that it does not have to be in the web.config file.
Here's a starting point. It doesn't do exactly what you want, but it illustrates the concept of virtualizing the configuration.