Instructions thrown together By TobinHarris , and copy-edited by Olle Jonsson.
I’ve recently needed to make a RubyOnRails web app “talk” to .NET, and chose to use a set of internal .NET web services as the integration layer. Getting it working was a bit of a pain, and took me quite a few hours. Despite Googling it to death, I still couldn’t find any conclusive article
There are a few steps needed to get this working.
1. Create a service wrapper class which describes the service you want to talk to. This is just a simple class that doesn’t really do anything other than describe the service you want to call.
This class will be called something like CrystalReportsAPI, will inherit from ActionWebService::API::Base class, will have a filename such as crystal_reports_api.rb and live in the /app/apis folder.
Example:
class CrystalReportsAPI < ActionWebService::API::Base api_method :TriggerMonthlyNewsletter, :expects=>[{:newsletterId=>:int},{:startDate=>:string}], :returns=>[:int]end
2. Pick a web controller that needs to call the functionality of your .NET web service, and add a line such as:
class SomeController < ApplicationController
...
web_client_api :my_service, :soap, "http://localhost:8080/CrystalReportsService.asmx", :namespace=>"http://www.mycompany.com", :driver_options=>{:default_encodingstyle => SOAP::EncodingStyle::ASPDotNetHandler::Namespace }
...
Be sure to replace the URI with one that actually points to your service (the page that lists all the WebMethods available in the service).
3. You are now possibly in a position to use your web service within your Rails controller.
def some_controller_action
@delivered = my_service.TriggerMonthlyNewsletter(1)
end
Dah dah! Behind the scenes Rails should execute a call to the .NET web service, and then return the return value output of that service call.
In a perfect world I’m sure this should all just work, but for me it didn’t. I had errors coming from .NET such as:
I had to tailor things a bit to get it all going. More specifically, I needed to decorate my .NET WebService class in a very specific way. Slight variations of this just didn’t work with all sorts of errors, so here’s the way I managed to get it going.
[SoapDocumentService(SoapBindingUse.Encoded, ParameterStyle=SoapParameterStyle.Wrapped,RoutingStyle=SoapServiceRoutingStyle.RequestElement)]
[WebService(Namespace = "http://www.company.com")]
public class CrystalReportsService : System.Web.Services.WebService
{
...
}
Note that first SoapDocumentService attribute – this is the key thing!
You may still be bumping into trouble. Try these:
... :namespace => "http://www.mycompany.com" ...
api_method :DoSummat, :expects=>[{:name=>:string}]
rather than this, which won’t work:
api_method :DoSummat, :expects=>[:string]
If you’re passing XML or HTML as a string parameter to a web service, you’re asking for trouble :-) For example:
//c# web service method
[WebMethod]
public string ParseHtml(string theHtml)
{
//...
}
When posting HTML, Rails will automatically encode the string into Base64 so that it can be safely embedded into the SOAP envelope. When it gets to the web service, .NET will try to parse the parameter and realise it is of the wrong type, thus barfing badly.
The best way to cope with this problem is to have your .NET web method receive a byte[] and then decode it from Base64. Of course, if you change your signature in .NET, you will also need to update the Rails service wrapper class to expect a :base64 type rather than a :string.
Okeydoke, I’ll add any more here details and wrinkles here, as I find them. Hope that I’ve not totally done all this the wrong way – I’m sure it should have all just worked “out of the box”, so perhaps I missed something!
This worked for me and helped a lot. Thanks so much.
I would like to add that you’d need to include “using System.Web.Services.Description;” directive at the top of your .NET code, in order to be able to use “SoapBindingUse” as my code did not compile after added that line.
signature is very important, remember to use {:name => :type} way and not just [:type], otherwise .NET cannot see the values.
you can get the name & type from the wsdl of the web service.
keywords:
.NET, DotNet, csharp, c#, VB.NET WebServices, ActionWebService, WebService, API
I found a significantly easier way to do this using the built in Ruby SOAP library. See the tutorial on my blog below:
http://webgambit.wordpress.com/2007/01/10/calling-a-net-web-service-from-rails-original/
h2. This might be even easier with 1.2
One of DHH’s main points in his recent keynote was a move to CRUD for controller actions, and integrating REST into the framework. ActiveResource will:
> abstract a REST webservice built following certain conventions, similar to how ActiveRecord currently abstracts a relational database.
Instructions thrown together By TobinHarris , and copy-edited by Olle Jonsson.
I’ve recently needed to make a RubyOnRails web app “talk” to .NET, and chose to use a set of internal .NET web services as the integration layer. Getting it working was a bit of a pain, and took me quite a few hours. Despite Googling it to death, I still couldn’t find any conclusive article
There are a few steps needed to get this working.
1. Create a service wrapper class which describes the service you want to talk to. This is just a simple class that doesn’t really do anything other than describe the service you want to call.
This class will be called something like CrystalReportsAPI, will inherit from ActionWebService::API::Base class, will have a filename such as crystal_reports_api.rb and live in the /app/apis folder.
Example:
class CrystalReportsAPI < ActionWebService::API::Base api_method :TriggerMonthlyNewsletter, :expects=>[{:newsletterId=>:int},{:startDate=>:string}], :returns=>[:int]end
2. Pick a web controller that needs to call the functionality of your .NET web service, and add a line such as:
class SomeController < ApplicationController
...
web_client_api :my_service, :soap, "http://localhost:8080/CrystalReportsService.asmx", :namespace=>"http://www.mycompany.com", :driver_options=>{:default_encodingstyle => SOAP::EncodingStyle::ASPDotNetHandler::Namespace }
...
Be sure to replace the URI with one that actually points to your service (the page that lists all the WebMethods available in the service).
3. You are now possibly in a position to use your web service within your Rails controller.
def some_controller_action
@delivered = my_service.TriggerMonthlyNewsletter(1)
end
Dah dah! Behind the scenes Rails should execute a call to the .NET web service, and then return the return value output of that service call.
In a perfect world I’m sure this should all just work, but for me it didn’t. I had errors coming from .NET such as:
I had to tailor things a bit to get it all going. More specifically, I needed to decorate my .NET WebService class in a very specific way. Slight variations of this just didn’t work with all sorts of errors, so here’s the way I managed to get it going.
[SoapDocumentService(SoapBindingUse.Encoded, ParameterStyle=SoapParameterStyle.Wrapped,RoutingStyle=SoapServiceRoutingStyle.RequestElement)]
[WebService(Namespace = "http://www.company.com")]
public class CrystalReportsService : System.Web.Services.WebService
{
...
}
Note that first SoapDocumentService attribute – this is the key thing!
You may still be bumping into trouble. Try these:
... :namespace => "http://www.mycompany.com" ...
api_method :DoSummat, :expects=>[{:name=>:string}]
rather than this, which won’t work:
api_method :DoSummat, :expects=>[:string]
If you’re passing XML or HTML as a string parameter to a web service, you’re asking for trouble :-) For example:
//c# web service method
[WebMethod]
public string ParseHtml(string theHtml)
{
//...
}
When posting HTML, Rails will automatically encode the string into Base64 so that it can be safely embedded into the SOAP envelope. When it gets to the web service, .NET will try to parse the parameter and realise it is of the wrong type, thus barfing badly.
The best way to cope with this problem is to have your .NET web method receive a byte[] and then decode it from Base64. Of course, if you change your signature in .NET, you will also need to update the Rails service wrapper class to expect a :base64 type rather than a :string.
Okeydoke, I’ll add any more here details and wrinkles here, as I find them. Hope that I’ve not totally done all this the wrong way – I’m sure it should have all just worked “out of the box”, so perhaps I missed something!
This worked for me and helped a lot. Thanks so much.
I would like to add that you’d need to include “using System.Web.Services.Description;” directive at the top of your .NET code, in order to be able to use “SoapBindingUse” as my code did not compile after added that line.
signature is very important, remember to use {:name => :type} way and not just [:type], otherwise .NET cannot see the values.
you can get the name & type from the wsdl of the web service.
keywords:
.NET, DotNet, csharp, c#, VB.NET WebServices, ActionWebService, WebService, API
I found a significantly easier way to do this using the built in Ruby SOAP library. See the tutorial on my blog below:
http://webgambit.wordpress.com/2007/01/10/calling-a-net-web-service-from-rails-original/
h2. This might be even easier with 1.2
One of DHH’s main points in his recent keynote was a move to CRUD for controller actions, and integrating REST into the framework. ActiveResource will:
> abstract a REST webservice built following certain conventions, similar to how ActiveRecord currently abstracts a relational database.