This question is a follow up to #joshperry's answer on CustomQueryStringConverter. I implemented this solution with a small modification. My version converts System.Int32[] instead of string[].
However, I have a problem with my WCF configuration. My service dishes out SOAP, XML and JSON. SOAP wasn't a problem, this solution works for XML, but JSON is still messed up. I tried found out that the class that does JSON conversion automatically (enableWebScript behavior) is a sealed class, so I can't override it like you did for WebHttpBehavior. I also tried adding two behaviors, but that didn't work either:
<behaviors>
<endpointBehaviors>
<behavior name="xmlBehavior">
<ArrayQuerystring />
</behavior>
<behavior name="jsonBehavior">
<ArrayQuerystring />
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
I think it might be an ordering issue? If I put the ArrayQuerystring behavior first, I get no results. If I put it second, then I get the same results as the XML endpoint. How do I apply your CustomQuerystringConverter to a JSON endpoint?
The JSON parser already supports arrays. You can pass them on the URL line like this:
...?ID=2&includedCollections=["Addresses","Phones"]
Related
I was wondering if service throttling is automatically applied when reliable session is used. I couldn't find a definitive answer while searching the web and msdn.
I'm inclined to think you have to put <serviceThrottling /> in the <serviceBehavior /> element for it to be enabled.
The thing is, that different blogs like this one throw me off by saying that you should watch out for the default throttling values.
That's my question in general, but I would also like to know the answer for my particular situation. My config currently has the following behavior:
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
As you can see I do not include the <serviceThrottling /> element. Is Throttling enabled anyway or did I successfully prevent throttling with this config?
Edit:
I just checked runtime on the server in OperationContext.Current.Channel.ChannelDispatcher.Endpoints.owner.ServiceThrottle and its value is null. This makes me lean more towards the idea that ServiceThrottling is disabled.
However I'm not quite sure if this is the right path to check, nor am I sure if this just doesn't mean that because it's null some default stuff will be used instead in the WCF core somewhere.
According to <serviceThrottling> on MSDN, these are the default values:
maxConcurrentCalls Default value is 16 * processor count. Setting it to 0 sets the value to Int32.MaxValue.
maxConcurrentInstances Default value is the sum of maxConcurrentCalls and maxConcurrentSessions.
maxConcurrentSessions Default value is 100 * processor count. Setting it to 0 sets the value to Int32.MaxValue.
So in your case, if you had 4 processors, your service would support 64 concurrent calls, 400 concurrent sessions and 464 concurrent instances.
Generally in my experience with WCF, default values are used even if you don't specifically include an empty tag. For example, the <security> tag can be omitted from a binding, and the default values for security will be used anyway.
To find the answer we did some load testing and came to the conclusion that even if you don't add the <serviceThrottling /> section to the config file and even though the ServiceThrottling property on the endpoint is null when observed in Debug, WCF still does throttling and uses the defaults as referenced by Tim to do it.
Let say I have a WCF
Foo(int param);
The client is passing in a JSON string. Instead of passing in an integer, they pass in a string.
The system now returns a 500 error back to the client. The event log says that I need to add includeExceptionDetailInFaults="true" to my config file if I want a friendly message to be returned. I go and do that but then I still get the 500 error and an event log error stating that I cannot add the 'serviceDebug' extension to my endpoint behavior because the underlying behavior type does not implement the IEndpointBehavior.
What does that suppose to mean?
First of all: where did you add the <serviceDebug> behavior, and how? Can you show us? The <serviceDebug> needs to be added to the <serviceBehavior> section on your server - not the endpoint behavior section. It's a service behavior, after all (it affects the whole service) - not an endpoint behavior (which affects only a single endpoint but not others).
So you should have:
<serviceBehaviors>
<behavior name="debug">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
in your server-side config (web.config or app.config), and then apply that service behavior to your service tag:
<services>
<service name="...."
behaviorConfiguration="debug">
....
Secondly: error 500 is an internal server error, so this means, the server couldn't interpret and handle your input. The best bet would be to do some client-side validation before actually sending this input to the service, to avoid these kind of errors.
If you cannot do this, then maybe you need to add some more logic to your service so you can capture and figure out these kind of errors before they blow up your service code.
And thirdly, the ultimate solution: you could write a client-side parameter inspector to catch these wrong parameters even before they're being sent to the server, and react accordingly. WCF is very extensible that way. See the MSDN How To Inspect Or Modify Parameters or this blog post if you're interested in learning more about parameter inspectors.
We have an application where we wish to expose an large number of database entities and some business logic. Each entity will require the ability to Read , Add, and Update. at this point we do not expect to allow deletion.
the software we build is used in a wide range of business, so of which are multi tenanted operations Bureau services, also some of our clients use this approach to have separate databases for financial reasons.
We wish to be able to minimize the number of endpoints that need to be maintained. At the moment there are only 3 tables be exposed as WCF interfaces each with 6 attached methods. this is manageable but if operation has 50 databases that suddenly becomes 150 endpoints. worse if we have 50 tables exposed that becomes 2500 endpoints.
Does anyone have a suggestion on how we could design out system that we still have a simple entity model of Job.add (var1) or iList jobs = Job.GetSelected("sql type read").
without all these endpoints
WCF Data Services allows you to expose your data in a RESTful manner using the Open Data protocal (OData). This was formally called ADO.Net data services and before that Astoria. Any IQueryable collection can be exposed. The way shown in most of the examples is to use the Entity Framework, however there are examples showing usage with NHibernate and other Data Access technologies. OData is a self describing API based on Atom-Pub with some custom extensions. With a minimal amount of code you can expose you're entire database in a well defined format. That's the easy part.
In order to implement multi-tenency, you can create query interceptors in the WCF Data Services application to implement that logic. The number of interceptors and the complexity of the code you write will depend upon your security model and requirements. Looking at something like T4 templates or CodeSmith to generate the interceptor methods based on your database schema may be a way to prevent lots of repetitive manual coding.
The link I provided has a lot of information and tutorials on WCF Data Services and would provide a good place to start to see if it would meet your needs. I have been looking at WCF Data Services for a similar problem (Multi-tenancy), and would love to hear how you evently implement your solution.
It seems like you could pass the "identity" to every query and take that into account. This would mean that every record on your "Job" table would need to have a reference to the owner "identity" but that should not be much of a problem.
Just make sure that every query validates the "identity", and you should be OK.
If I understand your question correctly, I think you need unique endpoints but you can have a single service behavior that your end points reference.
Create a default endpoint:
<behaviors>
<serviceBehaviors>
<behavior name="MyService.DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
Set your default binding:
<bindings>
<wsHttpBinding>
<binding name="DefaultBinding">
<security mode="None">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Have all service reference point to the default behavior and binding:
<service behaviorConfiguration="MyService.DefaultBehavior"
name="MyService.Customer">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="DefaultBinding"
contract="MyService.ICustomer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
Each time you add a service, its a simple config entry.
With Apache you can use a fairly simple set of URL rewriting rules to map an arbitrary set of DB table tables and their corresponding endpoints to a single endpoint with a parameter.
For example, to map $ROOT/table_name/column_name to $ROOT/index.php?tn=table_name&cn=column_name, you could add a rule like this to $ROOT/.htaccess:
RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/?$ index.php?tn=$1&cn=$2 [QSA,L]
Then you only need to maintain $ROOT/index.php (which of course can generate the appropriate HTTP status codes for nonexistent tables and/or columns).
Providing Multi-Tenancy, Without A Bazillion End Points
One way is to go with a REST-style WCF service that can use username/passwords to distinguish which client you are working with, and thus be able to select internally which DB to connect to. WCF gives you the the UriTemplate which allows you to map part's of the URL to the param's in your web methods:
HTTP GET Request: http://www.mysite.com/table1/(row Id)
HTTP PUT Request: http://www.mysite.com/table1/(row Id)/(field1)/(field2)
HTTP POST Request: http://www.mysite.com/table1/(row Id)/(field1)/(field2)
HTTP DELETE Request: http://www.mysite.com/table1/(row Id)
You can add other Uri Templates for more tasks as well, such as the following:
HTTP GET Request: http://www.mysite.com/table1/recentitems/(number of most recent items)
HTTP GET Request: http://www.mysite.com/table1/cancelPendingOrders/(user Id)
Who's Using My Service?
By requiring clients to supply a username and password, you can map that to specific DB. And by using the UriTemplate of /{tableName}/{operation}/{params...} you could then use code in your web service to execute the DB procedures given the table, operation, and params.
Wrapping It Up
Your web configuration wouldn't need to be altered much at all even. The following web article series is a great place to learn about REST-style web services, which I believe fits what you need: http://www.robbagby.com/rest/rest-in-wcf-blog-series-index/
I'm currently using Castle-Windsor with the WCF Facility to inject all my WCF services. I've just started adding permission requirements using a custom IAuthorizationPolicy, which seems to work when done on a per-method basis on the service, but when the service class itself is marked up with the requirements, I get an exception thrown.
I've set things up based on the example at How To – Use Username Authentication with Transport Security in WCF from Windows Forms. I didn't set up the custom HTTP Module class as I'm using an existing Membership implementation. My IAuthorizationPolicy implementation (HttpContextPrincipalPolicy) is essentially identical.
The essential part of my Web.config is:
<serviceBehaviors\>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseAspNetRoles"
roleProviderName="UserProvider">
<authorizationPolicies>
<clear/>
<add policyType="Website.FormsAuth.HttpContextPrincipalPolicy,Website"/>
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
Everything seems to work fine when I put the requirements on the method. This is being done like so:
[PrincipalPermission(SecurityAction.Demand, Role = RoleNames.USER_ADMINISTRATION)]
If this is on an OperationContract method, things work as expected. However, if it is moved to the class itself (which implements the ServiceContract) I get the following exception (with most of the extra stuff pruned out):
Castle.MicroKernel.ComponentActivator.ComponentActivatorException {
Message = "ComponentActivator: could not instantiate Services.UserService"
InnerException = System.Reflection.TargetInvocationException {
Message = "Exception has been thrown by the target of an invocation."
InnerException = System.Security.SecurityException {
Message = "Request for principal permission failed."
}
}
}
I've debugged and found that the constructor on HttpContextPrincipalPolicy is being called but Evaluate() is not when the demand is attached to the class. When it is attached to the method Evaluate() is being called. So at this point I've gone as far as my newbie .NET/WCF/Castle-Windsor skills will take me.
Is there a way to tell Castle-Windsor to invoke the service constructor while honoring the IAuthorizationPolicy? Or tell WCF that Evaluate() needs to be called for the creation of the class? Or is there some other way around WCF that does the same thing? I don't want to have to mark up every single method with the exact same bit of attribute declaration.
When you mark the class itself up with a PrincipalPermissionAttribute it's effectively saying to the runtime that at the point when the class is used the permission demand must be met. So now when Castle-Windsor is trying to instantiate the class, the permission demand is being made and of course it can't be fulfilled because the security context isn't established correctly at that point.
AFAIK, PrincipalPermissionAttribute is not supported on the class level for WCF due to the nature of its runtime even though it is allowed from a pure .NET perspective. Castle-Windsor is therefore unable to create your service instance for the same reason.
I am specifically looking for an example which use a) WCF & REST. After a long googling, though I got some but they are beyond my understanding.
Could some one please give me a very simple example say "Hallow World" or Summation of 2 numbers which will give me a clear insight about how to write a server, and also how to consume the same from the client end.
Also if any good link that explains this kind of example in simple terms kindly tell me that.
Thanks
REST in WCF is not that hard once you figure it out.
First you must define your interface.
Here is an example.
[ServiceContract]
public interface IRESTExample
{
[WebGet(UriTemplate = "interaction/queue?s={site}", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
[OperationContract]
string QueueInteraction(string site);
[WebGet(UriTemplate = "interaction/cancel?id={interactionId}", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
[OperationContract]
string CancelInteraction(string interactionId);
[WebGet(UriTemplate = "queue/state?s={site}&q={queue}", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
[OperationContract]
string QueueState(string site, string queue);
}
You can see in the WebGet you define the final URL. So it depends on where you bind it, but say you bind the endpoint to www.example.com/rest
QueueInteraciton would be www.example.com/rest/interaction/queue?s=SomeSite
Where {stie} or {parameterName} is replaced with the name of the parameter.
The implemetion is just a simple class, I am going to assume you know how to implement an interface. If you need help just leave a comment.
Now binding the endpoint. In the end it is not that hard, you can do it all in the config.
<system.serviceModel>
<services>
<service name="Stackoverflow.Example.Service.RestExample" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="http://localhost:2136/RestExample"/>
</baseAddresses>
</host>
<endpoint address="rest" binding="webHttpBinding" behaviorConfiguration="xmlBehavior" contract="Stackoverflow.Example.Service.IRESTExample" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<!-- Add the following element to your service behavior configuration. -->
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
<behavior name="xmlBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name = "NoSecurity">
<security mode = "None" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
Now the code to start the service and bind it. YOu can do it in anything, for example a console app.
RestExample exampleService = new RestExample();
host = new ServiceHost(exampleService);
host.Open();
This should be enough to get started.
msdn article An Introduction To RESTful Services With WCF with code example at msdn code gallery. Also check out this codeproject article
David Basarab's response is correct, but there's a much simpler way to do this without all the manual wire-up. Especially if you've used to classic ASMX web services and don't have a lot of WCF experience, the following method is dirt simple.
In a Visual Studio 2010 web project, add a reference to System.ServiceModel.Web.
Chose "add new item" in your project. The template you want is in "Web" and is called "AJAX-enabled WCF Service". Don't choose the vanilla "WCF Service"! If you do you have to do all the web.config wiring yourself that David Basarab described, and it's a pain. The "AJAX-enabled WCF Service" does all that setup for you. Name your service whatever you want.
Open up the .svc file. In the [ServiceContract] attribute on your class, fill in the Namespace string parameter with whatever you want.
You'll get a sample DoWork() method and a bunch of comments telling you what to do in the file. The trick to getting the RESTful API is to add [WebGet()] attributes to your web methods. Add one to DoWork() and verify everything functions for you.
So, to call the DoWork() method, you'd hit this in your browser:
http://localhost/MyAjaxEnabledService.svc/DoWork
Let's add a new HelloWorld() method now that shows some parameters and output.
VB:
<OperationContract()>
<WebGet(ResponseFormat:=WebMessageFormat.Xml)>
Public Function HelloWorld(ByVal name As String) As String
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml"
Return String.Format("Hello, {0}!", If(String.IsNullOrWhiteSpace(name), "world", name))
End Function
C#:
[OperationContract()]
[WebGet(ResponseFormat=WebMessageFormat.Xml)]
public string HelloWorld(String name) {
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
Return String.Format("Hello, {0}!", String.IsNullOrWhiteSpace(name) ? "world" : name);
}
Now you can visit:
http://localhost/MyAjaxEnabledService.svc/HelloWorld?name=MattMc3
There's a lot of crappy and confusing documentation out there about WCF, especially for those who crave the simplicity of the old .ASMX style. Hopefully this helps someone get started with WCF. There's a lot more you can do with it than the old ASMX-style, but it's hard to ramp up and not get discouraged with MS for their poor help with the transition from ASMX. You can read more about quick-and-dirty RESTful WCF services here.
If you really want to do ReST then use a web framework that will lead you down the right path. See OpenRasta.
It is not impossible to do WCF to do ReST, it is just very difficult to learn how to do Rest with a framework that will frequently get in your way and lead you in the wrong direction.
In Microsoft Web Developer, you can use the Online Template "WCF REST Service." It will set up a project for you with the correct web.config and global.asax files.
You can create an WCF REST web service by configuring your endpoint to use a webHttpBinding as seen in this in-depth tutorial:
http://www.west-wind.com/weblog/posts/310747.aspx
Here is another open source web services framework that simplifies creating XML and JSON REST web services without requiring any extra configuration.
Edit: Added link to good article articulating the spirit of REST:
http://tomayko.com/writings/rest-to-my-wife
Link to blog post comment explaining common misconceptions of REST:
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven