I am very new to web service stuff so please be kind.
I have written a simple POJO class, and deployed it on an axis2 server:
public class Database {
private Project project;
public void login(){
project = new Project();
project.setDescription("Hello there");
project.setName("To me");
}
public Project getProject(){
return project;
}
}
I call the service from a c# client:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr = db.getProject();
When I debug the response is null.
At the java end, when I call getProject, the project object is null.
What's happening?
How do I preserve the state of project between service calls?
For most toolkits, web services are stateless by default. I think axis is no different.
If you want to maintain state between calls then you will need to enable sessions. An example on how to maintain sessions in axis can be found at:
http://kickjava.com/src/test/session/TestSimpleSession.java.htm
On the .NET side you will need to assign a CookieContainer to your request to store the session identifier. See HOW TO: Use CookieContainer to Maintain a State in Web Services for more information.
I think your code would look something like this:
localhost.Database db = new WindowsFormsApplication1.localhost.Database();
// Assign the CookieContainer to the proxy class.
db.CookieContainer = new System.Net.CookieContainer();
db.login();
localhost.getProjectResponse pr = new WindowsFormsApplication1.localhost.getProjectResponse();
pr.CookieContainer = db.CookieContainer;
pr = db.getProject();
I think that should let you do what you want -- but I wouldn't recommend it.
Designing service interfaces is a bit different than designing object oriented interfaces. Service interfaces typically eschew the use of state and instead require the consumer to provide all of the relevant information in the request.
From Service-Oriented Architecture:
Services should be independent,
self-contained requests, which do not
require information or state from one
request to another when implemented.
I would definitely recommend reading that article and perhaps revisiting your design.
I'm not sure why #shivaspk left a comment instead of writing an answer, it is quite correct: web service calls (not just axis calls) are meant to be stateless, so although the project object gets created by
db.login();
when you call
db.getProject();
It is being called on a different instance of your Database class that was created by Axis to service the second call.
There is no really good answer to your question, except for you to rethink what you are trying to do. If you need some kind of authentication (via login), then that authentication needs to be part of every web service call.
Related
I have a web application which is a mesh of a few different servers and 1 server is the front-end server which handles all request external incoming requests.
So some of these request will have to be passed along to different servers and ideally the only thing I want to change is the host and Uri fields of these request. Is there a way to map an entire incoming request to a new outgoing request and just change a few fields?
I tried something like this:
// some controller
public HttpResponseMessage get()
{
return this.Request.Rewrite("192.168.10.13/api/action");
}
//extension method Rewrite
public static HttpResponseMessage Rewrite(this HttpRequestMessage requestIn, string Uri) {
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpRequestMessage requestOut = new HttpRequestMessage(requestIn.Method, Uri);
requestOut.Content = requestIn.Content;
var headerCollection = requestIn.Headers.ToDictionary(x => x.Key, y => y.Value);
foreach (var i in headerCollection)
{
requestOut.Headers.Add(i.Key, i.Value);
}
return httpClient.SendAsync(requestOut).Result;
}
The issue I am having is that this has a whole slew of issues. If the request is a get Content shouldn't be set. THe headers are incorrect since it also copies things like host which shouldn't be touched afterwards etc.
Is there an easier way to do something like this?
I had to do this in C# code for a Silverlight solution once. It was not pretty.
What you're wanting is called reverse proxying and application request routing.
First, reverse proxy solutions... they're relatively simple.
Here's Scott Forsyth and Carlos Aguilar Mares guides for creating a reverse proxy using web.config under IIS.
Here's a module some dude named Paul Johnston wrote if you don't like the normal solution. All of these focus on IIS.
Non-IIS reverse proxies are more common for load balancing. Typically they're Apache based or proprietary hardware. They vary from free to expensive as balls. Forgive the slang.
To maintain consistency for the client's perspective you may need more than just a reverse proxy configuration. So before you go down the pure reverse proxy route... there's some considerations.
The servers likely need to share Machine Keys to synchronize view state and other stuff, and share the Session Store too.
If that's not consistent enough, you may want to implement session stickiness through Application Request Routing (look for Server Affinity), such that a given session cookie (or IP address, or maybe have it generate a token cookie) maps the user to the same server on every request.
I also wrote a simple but powerful reverse proxy for asp.net / web api. It does exactly what you need.
You can find it here:
https://github.com/SharpTools/SharpReverseProxy
Just add to your project via nuget and you're good to go. You can even modify on the fly the request, the response, or deny a forwarding due to authentication failure.
Take a look at the source code, it's really easy to implement :)
I'm new to Web Services from C#, but have worked C# for years, just never needed to use Web Services. Due to privacy issues, I can't disclose actual URL, but there is a test server and a production server where the web services are identical in all other respects, and the services were written / managed by another entity.
https://LiveSite.SomeDomain.com/FolderInWebSite/TestWebServiceSoapHTTP
and
https://TestSite.SomeDomain.com/FolderInWebSite/TestWebServiceSoapHTTP
Do I need to create two separate web references to the project and create different instances of them to go, or can I via some property just change which URL version it is sending data to.
Additionally, not being familiar working web services, I see the classes as Visual Studio imported. I can create instances of the classes and set the applicable properties (int, dates, strings, string[] arrays, etc). But not seeing how to actually say ... Go send it now. and then getting the response back.
I've done this from an older application with another language and was doing direct with HTTP and SOAP where I was able to make my own connection to the URL, build the body of the SOAP message, then send it.
Just use the "Url" property.
var myProxy = new MyProxy();
myProxy.Url = "http://foo.com/myservice";
Edit for second part of the question:
There should be a method for each action exposed the API that you can call. For example if the API exposes a MyAction that takes a string, the code generator should have generated a method that you can use like so:
myProxy.MyAction("hello");
I have written a WCF service with some regular functionality (add user, remove, search, update...). The implementation of this functionality is in entity framework (with sql DB).
Now I want to use it in the client side.
And I have some basic questions:
I have many calls to the WCF methods in the client side - should I try catch every time each call?
Every time I want to call a method, for example AddUser(User user), I need to make an instance of my service, like that:
WcfService client = new WcfService();
client.AddUser(user);
And in another place I write:
WcfService client = new WcfService(); //Again making a new instance...
client.UpdateUser(user);
Should I make one instance for all the application for my wcf service?
Or every time to make a new instance before I call to a method? (as in my example above).
Thanks very much !
In many cases, you want to reuse the same client proxy, as this connection method yields the best performance. Reusing the same proxy can be particularly beneficial if you use security features, which have a high initial security negotiation cost. Note: you surely need to check the state of the client proxy before using.
In the event that reusing the same client proxy is not an option, then consider using a ChannelFactory proxy that uses caching.
The following link provides a good explanation along with best practice recommendations:
http://blogs.msdn.com/b/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx
(i)You can make an instance one time for a service, and use the same client whenever you need to make a method call. if you are aborting or closing the connection then you need to create each time.
(ii)It is better if you use try catch methods in each methods, so it will be easy to close the connection and identify the exceptions.
I am trying to get data form a web service inside a silverlight app. Unfortunately the silverlight app (Bing map app) just hangs when trying to connect.
I use the same code in a console app and it works just fine.
Is there anything special I need to do in silverlight to get it to work? I don't get any exceptions - it just hangs.
I based my service and client code off of this example
http://www.switchonthecode.com/tutorials/wcf-tutorial-basic-interprocess-communication
Problems and Questions:
1. Why can't I set breakpoints in my sliverlight code?
2. How can I successfully call WCF service from a silverlight app? (links to SIMPLE working examples would be great - all the ones I seem to find seem to be quite advanced (RIA, Duplex, etc) Many of these also show xml and other non C# "code" - frankly I don't know what those do and how they relate to the projects, code and services.
(Clearly I am quite ignorant about WCF and silverlight)
As per request for code:
[ServiceContract]
public interface ILGSMapServer
{
[OperationContract]
List<double> GetLatitudes();
}
public class TreeWorkClient
{
ChannelFactory<ILGSMapServer> httpServer;
public ILGSMapServer httpProxy;
public TreeWorkClient()
{
httpServer = new ChannelFactory<ILGSMapServer>(new BasicHttpBinding(), new EndpointAddress("http://localhost:8000/GetLatitudes"));
httpProxy = httpServer.CreateChannel();
}
public List<TreeWorkItem> GetLocations()
{
List<double> lats = httpProxy.GetLatitudes();
//... do stuff in code
return ret;
}
}
I agree with John Saunders - it would be easier to answer this if you published the client code.
However as a guess, a common problem with calling services from Silverlight applications is the restriction Silverlight puts on cross domain calls.
In summary, if your service is at a different domain from the site-of-origin of the Silverlight application, you need to create a client access policy file at the service location.
See this for details:
http://msdn.microsoft.com/en-us/library/cc197955(v=vs.95).aspx
Given your example code you should be seeing the
System.InvalidOperationException: The contract 'ILGSMapServer'
contains synchronous operations, which are not supported in
Silverlight. Split the operations into "Begin" and "End" parts and set
the AsyncPattern property on the OperationContractAttribute to 'true'.
Note that you do not have to make the same change on the server.
You'd need to change your service contract to the following
[ServiceContract]
public interface ILGSMapServer {
[OperationContract( AsyncPattern = true )]
IAsyncResult BeginGetLatitudes( AsyncCallback callback, object context );
List<double> EndGetLatitudes( IAsyncResult result );
}
This also means you'll need to do something completely different in your GetLocations() function as this function will return before the results from the Web have been returned.
Try taking a look at the examples here.
Other options involve using the "Add Service Reference" rather than manually defining it in code.
I believe you need to have this attribute on WCF service for SL to consume it:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
As for debugging - you can debug Silverlight, try using IE for that, its most natural browser for SL debugging (sadly).
Once you start debugging it will be more clear whats wrong when you catch cross domain exception or some other.
What is the best practice when you need to authenticate specific OperationContracts, while using the default MembershipProvider for security (FormsAuthentication).
I guess that doing Membership.ValidateUser and Membership.GetUser just won't cut it when using WebServices, right?
In other words: How can I verify that a user is allowed to use specific methods in the webservice (that the user is authenticated/"logged on")?
Yeah--you can't really use FormsAuthentication in this case. But there is excellent infrastructure available in WCF for managing role-based access to individual methods: http://msdn.microsoft.com/en-us/magazine/cc948343.aspx
I have been known to over-engineer things, so when I use WCF in my web applications, I wrap the service in my web app. This way my web app calls the abstraction.
Now, what you can do is apply your code access security (CAS) on the wrapper.
Example code might look like this (tons of details omitted for brevity)
internal class ServiceWrapper
{
Service Svc;
public ServiceWrapper()
{
Svc = ServiceClient();
}
[System.Security.Permissions.PrincipalPermission(System.Security.Permissions.SecurityAction.Demand, Role = "HelloWorld")]
public string HelloWorld()
{
return Svc.HelloWorld();
}
}
In a perfect world, we would want CAS to be a bit more dry (don't repeat yourself), meaning handled in the WCF as you suggest. But this might be a good middle of the road if know you can lock down your WCF app and control who calls it :-)
That would help you simplify getting the ball rolling...
Good luck!