I want to do some checking in WCF before calling Operation.
My code is as below
public RESTService()
{
if (ConfigurationManager.AppSettings("BlockLogin") == "1")
{
HttpContext.Current.Response.Write("{""Status"" : ""Service under maintainance""}");
HttpContext.Current.Response.End()
}
}
I was expecting that it would end the request and won't call operation contract (getTokenX in this case) but it does. How to make it stop calling operation contract?
my URL is like
172.16.3.156:81/_RestAPI/RestService.svc/getTokenX
You could also use the Global.asax file to control the validity of the request.
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (Flag==true)
{
Response.End()
}
}
I don’t recommend using httpcontext in the wcf application. In most cases, It is set for the asp.net application domain and its value is empty.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-services-and-aspnet
I would suggest following thing for solution.
Create custom service behaviour.
In that service behaiour check for specific appsetting the way you do.
if you found some value that indicate service in maintainance then throw exception.
Related
I'm consuming a clunky WCF server that occasionally throws various exceptions, and additionally returns some of its errors as string. I have no access to the server code at all.
I want to override the inner WCF-client request invocation method and handle all inner exceptions and hard-coded errors returned by the server and raise the Fault event if an error occurs, pseudo:
class MyClient : MyServiceSoapClient
{
protected override OnInvoke()
{
object result;
try
{
result = base.OnInvoke();
if(result == "Error")
{
//raise fault event
}
catch
{
//raise fault event
}
}
}
So that when I call myClient.GetHelloWorld(), it goes thru my overridden method.
How can this be achieved?
I know I don't have to use the generated client, but I don't want to re-implement all the contracts again, and I want to use the generated ClientBase subclass or at least its channel.
What I need is control over the inner request call method.
Update
I read this answer, and looks it's partially what I'm looking for, but I'm wondering if there is a way to attach an IErrorHandler to the consumer (client) code only, I want to add it to the ClientBase<TChannel> instance somehow.
Update
This article also looks very promising but it doesn't work. The applied attribute doesn't seem to take effect.
I can't find a way to add IServiceBehavior to the client side.
Update
I tried attaching an IErrorHandler via IEndpointBehavior.ApplyClientBehavior calling:
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers
.Add(new ErrorHandler());
}
(clientRuntime is a parameter), but exceptions are still thrown directly skipping MyErrorHandler.
ApplyDispatchBehavior isn't called at all.
Conclusion
I need to achieve two aspects:
Wrap all exceptions that might occur during the lifetime of a BaseClient<TChannel> and decide whether to handle them or throw them on. This should take care of all operation (the service I'm consuming exposes few dozens)
Parse all server-replies and throw exceptions for some of them, so they're forwarded as in statement 1.
You could use and modify the Exception Handling WCF Proxy Generator, more specifically, the base class that it uses. It's basic idea (check this description too) is to provide connection resilience by catching connection faults, and retrying the failed operation. As you can imagine, for this purpose it needs to be able to catch thrown exceptions, and also, it can inspect the result of calls.
The main functionality is given by the ExceptionHandlingProxyBase<T> base class, which you use instead of the ClientBase<T>. This base class has an Invoke method as follows, you'd need to modify that.
Simplified Invoke:
protected TResult Invoke<TResult>(string operationName, params object[] parameters)
{
this.Open();
MethodInfo methodInfo = GetMethod(operationName);
TResult result = default(TResult);
try
{
this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait);
result = (TResult)methodInfo.Invoke(m_channel, parameters);
}
catch (TargetInvocationException targetEx) // Invoke() always throws this type
{
CommunicationException commEx = targetEx.InnerException as CommunicationException;
if (commEx == null)
{
throw targetEx.InnerException; // not a communication exception, throw it
}
FaultException faultEx = commEx as FaultException;
if (faultEx != null)
{
throw targetEx.InnerException; // the service threw a fault, throw it
}
//... Retry logic
}
return result;
}
You'll need to modify the throw targetEx.InnerException; part to handle the exceptions as you need, and obviously the resturn value shoudl also be inspected for your needs. Other then that you can leave the retry logic or throw it away if you don't expect connection problems. There is another variant of the Invoke for void return methods.
Oh, and by the way, it works with duplex channels as well, there is another base class for those.
If you don't want to use the generator (it might not even work in newer versions of VS), then you could just take the base class for example from here, and generate the actual implementation class with T4 from your service interface.
If the service isn't returning a true exception, but just a message, you probably want to add a ClientMessageInspector as a new client behavior. Please see: https://msdn.microsoft.com/en-us/library/ms733786.aspx
I've ended up using something based on the answers in this question.
It sticks to the generated client code, and allows invocation of the operations generically.
The code is incomplete, feel free to fork and edit it. Please notify me if you found any bugs or made any updates.
It's pretty bulky so I'll just share the usage code:
using (var proxy = new ClientProxy<MyServiceSoapClientChannel, MyServiceSoapChannel>())
{
client.Exception += (sender, eventArgs) =>
{
//All the exceptions will get here, can be customized by overriding ClientProxy.
Console.WriteLine($#"A '{eventArgs.Exception.GetType()}' occurred
during operation '{eventArgs.Operation.Method.Name}'.");
eventArgs.Handled = true;
};
client.Invoke(client.Client.MyOperation, "arg1", "arg2");
}
I am making a project using WebServices in C#. I wanted to ask you, how can I give a value to a variable from Client to a Web Service?
For example:
In the web service I have a variable and two Methods, getVariable() and setVariable(bool a);
bool var = false;
[WebMethod]
public void setVariable(bool a)
{
var = a;
}
[WebMethod]
public bool getVariable()
{
return var;
}
This is how my web service looks (it's simple because I am learning).
My client:
//In the client I added the web service as a Service Reference and added this code:
ServiceReference.ServiceSoapClient obj = new ServiceReference.ServiceSoapClient();
private void Form_Load(object sender, EventArgs e)
{
obj.setVariable(true);
label1.Text = obj.getVariable().ToString();
}
And when I load my form, the label1.Text isn't equal with "True" but with "False"!! Which means that it didn't execute this code: obj.setVariable(true);
My professor said in the class something that WebService are now "full...." (but I couldn't hear it well), he said you have to find a way to make WebServices "ful..."
Can someone help me ?
Web services are stateless by default, which means that they don't retain state between calls. So a value set in one call won't be available for usage by the next call.
If you need a stateful service, there are several ways to go. this is probably the simplest.
It sounds like you are doing this for learning purposes, in which case I suggest reading up on why it is not a good practice to develop using stateful services. Try this one for starters.
Since web services are stateless you can't do what you are trying to do.
Although you have only one client instance, for each call a server-side instance gets created. That means that in the first call you set the variable on an object, which then goes out of scope (since it's tied to that request). When you do make the second call, a new instance of your service gets created and this new instance obviously has no knowledge of the previous one.
If you want to do something like that you need the save the state. This can be done in various ways:
Save the value in the Application object (HttpContext.Current.Application("myvar") = a)
Save it in session state (you need to add an attribute to the service class to enable session state, then you do the same as with the Application but accessing HttpContext.Current.Session
Save it in a database
Save it in a file
...
#I4V - Thanks for your comment on my post.
I just added static before the bool variables and it worked.
We have a service to update customer information to server. One service call takes around few seconds, which is normal.
Now we have a new page where at one instance around 35-50 Costumers information can be updated. Changing service interface to accept all customers together is out of question at this point.
I need to call a method (say "ProcessCustomerInfo"), which will loop through customers information and call web service 35-50 times. Calling service asynchronously is not of much use.
I need to call the method "ProcessCustomerInfo" asynchronously. I am trying to use RegisterAsyncTask for this. There are various examples available on web, but the problem is after initiating this call if I move away from this page, the processing stops.
Is it possible to implement Fire and Forget method call so that user can move away (Redirect to another page) from the page without stopping method processing?
Details on: http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx
Basically you can create a delegate which points to the method you want to run asynchronously and then kick it off with BeginInvoke.
// Declare the delegate - name it whatever you would like
public delegate void ProcessCustomerInfoDelegate();
// Instantiate the delegate and kick it off with BeginInvoke
ProcessCustomerInfoDelegate d = new ProcessCustomerInfoDelegate(ProcessCustomerInfo);
simpleDelegate.BeginInvoke(null, null);
// The method which will run Asynchronously
void ProcessCustomerInfo()
{
// this is where you can call your webservice 50 times
}
This was something I whipped just to do that...
public class DoAsAsync
{
private Action action;
private bool ended;
public DoAsAsync(Action action)
{
this.action = action;
}
public void Execute()
{
action.BeginInvoke(new AsyncCallback(End), null);
}
private void End(IAsyncResult result)
{
if (ended)
return;
try
{
((Action)((AsyncResult)result).AsyncDelegate).EndInvoke(result);
}
catch
{
/* do something */
}
finally
{
ended = true;
}
}
}
And then
new DoAsAsync(ProcessCustomerInfo).Execute();
Also need to set the Async property in the Page directive <%# Page Async="true" %>
I'm not sure exactly how reliable this is, however it did work for what I needed it for. Wrote this maybe a year ago.
I believe the issue is the fact is your web service is expecting a client to return the response to, that the service call itself is not a one way communication.
If you're using WCF for your webservices look at http://moustafa-arafa.blogspot.com/2007/08/oneway-operation-in-wcf.html for making a one way service call.
My two cents: IMO whoever put the construct on you that you're not able to alter the service interface to add a new service method is the one making unreasonable demands. Even if your service is a publicly consumed API adding a new service method shouldn't impact any existing consumers.
Sure you can.
I think what you are wanting is a true background thread:
Safely running background threads in ASP.NET 2.0
Creating a Background Thread to Log IP Information
I'm hosting WCF services in Asp.net web page in ASP.NET Compatibility Mode
(AspNetCompatibilityRequirementsMode.Allowed). I've written simple HttpModule:
public class ExceptionInterceptor : IHttpModule
{
public ExceptionInterceptor()
{
}
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.Error += new EventHandler(context_Error);
}
void context_Error(object sender, EventArgs e)
{
// do something
}
}
web.config:
<httpModules>
<add name="ExceptionInterceptor" type="HttpModules.ExceptionInterceptor, HttpModules"/>
</httpModules>
My question is, why after occurence of unhandled exception in service, the code do not enter in context_Error(object sender, EventArgs e) function in my module.
What's more, the code do not even enter the Application_Error(object sender, EventArgs e) in Globals.asax.
Can someone explain that to me ?
What is the best option for global exception handling in WCF services ?
Regards
WCF is not ASP.NET - it might be able to use some of ASP.NET's infrastructure, but it's not ASP.NET per se.
In order to handle errors in a WCF service globally, you need to implement the IErrorHandler interface on your service - or plug in a WCF behavior that does this for you.
Check out the MSDN documentation on IErrorHandler - it's quite a simple interface, really. The HandleError method is typically used to log the error on the server to keep track of what's going on, while the ProvideFault method is used to turn the .NET exception on the server into an interoperable SOAP fault to send that back to the calling client (which might be a non-.NET client that can't really deal with a .NET-specific exception).
Rory Primrose has a great blog post about how to package up the IErrorHandler into a WCF service behavior which you can easily add to an existing service just in config - pretty close to magic :-) Also, check out another great post on the topic by Steve Barbour.
long time ago I wrote webservice that is still in use. Now I plan to refactor it. The webservice is full of most likely unused functions and I have no idea how it is used by the clients. In order to strip away the unused functions I need to analyze the function calls and data of currently installed webservice.
Is there a (free/opensource) tool that will enable me to log all activities of the webservice.
The ideal output of the tool I'm looking for could be a database containing all the called functions and a list of the data that was send to it for each call.
Solution
With the help of Martins answer I created this HttpModule which does exactly what I wanted:
public class LoggingModule : IHttpModule
{
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
TryAppendLog("Content-Type");
TryAppendLog("SOAPAction");
}
void TryAppendLog(string key)
{
string value = HttpContext.Current.Request.Headers[key];
if (string.IsNullOrEmpty(value)) { return; }
HttpContext.Current.Response
.AppendToLog(string.Format("{0}: {1} ", key, value));
}
#region IHttpModule Member
public void Dispose() { }
#endregion
}
As Kobi wrote, you can find the required information in the IIS log files (i.e. in c:\WINDOWS\system32\LogFiles\W3SVC1).
If you want to log the usage into a database, you could write a simple HttpModule, which checks every request, and logs it into the DB if it is a call to your web service.
E.g. here's the relevant parts of a very simple HttpModule, which logs calls to mywebservice.asmx:
public class MyWebServiceDiagnosticsModule : IHttpModule
{
public MyWebServiceDiagnosticsModule ()
{
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
private void BeginRequest(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
string url = ctx.Request.Url.ToString().ToLower();
if (url.Contains("mywebservice.asmx"))
{
LogMethodCall(url); // parse URL and write to DB
}
}
}
You can potentially write your own IHttpHandler that would log all the information and then delegate the call to appropriate .NET HTTP Handler, but that wouldn't be a simple task.
And a word on terminology. "Refactoring" is not about changing external behavior, so if refactoring is really what you're heading for, I'd recommend to keep the public contract (interface) of the web service intact. Instead, roll out a new version of the same service with only core functionality.
You can enable logging in the IIS, they can get very detailed depending on your choices.
There are tools made specifically for analyzing IIS logs.
Depending a little bit on your load/criticality and similar constraints you could also probably just route the traffic through as Soap Proxy like SoapUI to capture and analyze traffic for a period of time. If you set up the proxy and re-route at the firewall level it should be transparent for end-users.
I have not tried this for a system with heavy load; be warned.