Switch between production and test Webservice - c#

Switch between production and test Webservice.
I have 2 version for the same WebService definition. Each version has its own database url etc.
MyLib.FooWebServicePROD.FooWebService _serviceProd;
MyLib.FooWebServiceTEST.FooWebService _serviceTest;
For now to siwtch form one to the other I used the Rename option in Visual Studio.
I would like to wrap all my instance and definition in a layer of abstration so the programe will not be edited everytime.
So I made mine singleton public sealed class FooBarWrap but with a huge amount a duplication like:
public bool Close()
{
if (_serviceProd != null)
{
_serviceProd.logout(guid);
log4N.Info("Closing PROD");
}
if (_serviceTest != null)
{
_serviceTest.logout(guid);
log4N.Info("Closing TEST");
}
return true;
}
public bool Login()
{
try
{
log4N.Info("Connection to FooBar webservice...");
if (isProd)
{
_serviceProd = new MyLib.FooWebServicePROD.FooWebService();
_serviceProd.Timeout = System.Threading.Timeout.Infinite;
_serviceProd.Logon(guid);
}
else {
_serviceTest = new MyLib.FooWebServiceTEST.FooWebService();
_serviceTest.Timeout = System.Threading.Timeout.Infinite;
_serviceTest.Logon(guid);
}
log4N.Info("done");
return true;
}
catch (Exception ex)
{
log4N.Info("failed !");
log4N.Error("Echec connexion au webservice FooBar", ex);
return false;
}
}
Is there a simplier way to achieve this? Without the client having a reference to one or the other web service, and without the heavy code duplication?
if (FooBarWrap.Instance.Login()){
//DoSomething
var ClientResult = FooBarWrap.Instance.SomeRequest()
}

Is there a simplier way to achieve this? Without the client having a reference to one or the other web service, and without the heavy code duplication?
It is.
You could simply use conditional dependency injection where depending on the environment you are or any other condition like host name, port number or url path, you would get different implementation of the service interface.
A simple conditional dependency injection that depending on condition provides one or the other implementation of the same interface.
kernel.Bind<ISomeService>().To<SomeService1>();
kernel.Bind<ISomeService>().To<SomeService2>().When(x => HttpContext.Current[host|port|url path] == "some value");
Ninject calls that kind of injection contextual binding
https://github.com/ninject/ninject/wiki/Contextual-Binding

Related

ClickOnce not passing second Uri

We have a WPF application, which uses WindowsFormsApplicationBase class to make it singleton; and is deployed using ClickOne. Whenever we wanted to execute this exe, we invoke it through Uri (deployed directory in server with query string). All works fine only for first instance of this application.
Problem: ClickOnce always passes the first Uri every time the single-instance application is activated regardless of what Uri is being passed. In addition, the StartupNextInstanceEventArgs is not populated for any subsequent instantiation of same application.
Has anyone had this issue?
Thanks in advance.
Well so far I haven't got any concrete answer for my question. Therefore, I decided implement a different solution which is mentioned here. Unfortunately, the original issue hold true in both approach. So i decided to do a workaround on top of the second approach (see the url) to solve this until I have a clean solution.
Workaround
Modified entry point (Main) to include a functionality, which saves the incoming activation uri to app config file. You must keep this position at which you save the value since it tended to override with old activation uri somewhere down the line. Remember this is my issue.
public static void Main()
{
string uri;
StartupHelpers.SetConfigurationValue("ActivationUri", (StartupHelpers.HasTriggeredFromUrl(out uri)) ? uri : string.Empty);
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
{
var application = new App();
application.Run();
SingleInstance<App>.Cleanup();
}
}
Now implement the interface (ISingletonInstanceApp) as below.
public bool SignalExternalCommandLineArgs(IList<string> args)
{
var uri = new Uri(StartupHelpers.GetConfigurationValue("ActivationUri"));
int queryString = 0;
if (StartupHelpers.IsTriggeredFromWLink(uri, out queryString))
{
//in my case I have a function LoadPage which take
//some parameter to populate UI. Your case might be
//totally different. However, the idea is on how we
//could grab running instance and pass value into
// it to do something different.
((YourMainWindow) (Current.MainWindow)).LoadPage(queryString.ToString());
}
// Bring window to foreground
if (this.MainWindow.WindowState == WindowState.Minimized)
{
this.MainWindow.WindowState = WindowState.Normal;
}
this.MainWindow.Activate();
return true;
}
Helper to get/set config values.
public static class StartupHelpers
{
public static bool HasTriggeredFromUrl(out string uri)
{
try
{
uri = string.Empty;
var activeUri = ApplicationDeployment.CurrentDeployment.ActivationUri;
uri = activeUri != null ? activeUri.ToString() : string.Empty;
return true;
}
catch (InvalidDeploymentException inv)
{
uri = string.Empty;
return false;
}
}
public static bool IsTriggeredFromLink(Uri activationUri, out int queryStringValue)
{
queryStringValue = 0;
var hasTriggeredFromLink = true;
if (string.IsNullOrWhiteSpace(activationUri.Query) ||
HttpUtility.ParseQueryString(activationUri.Query).Count <= 0)
hasTriggeredFromLink = false;
else
{
if (!int.TryParse(HttpUtility.ParseQueryString(activationUri.Query)[0], out queryStringValue))
throw new Exception("Invalid startup argument found from web site.");
}
return hasTriggeredFromLink;
}
public static bool SetConfigurationValue(string key, string value)
{
try
{
Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
appConfig.AppSettings.Settings[key].Value = value;
appConfig.Save(ConfigurationSaveMode.Full);
ConfigurationManager.RefreshSection("appSettings");
}
catch (Exception ex)
{
throw ex;
}
return true;
}
public static string GetConfigurationValue(string key)
{
try
{
Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationManager.RefreshSection("appSettings");
return appConfig.AppSettings.Settings[key].Value;
}
catch (Exception ex)
{
throw ex;
}
}
}
A bit of a late answer but I happened to stumble upon this while looking into forcing an application to a single instance.
If I understand what you are trying to do, you want a single instance app which takes command line parameters. The second time the app is attempted to be run, you just want to keep the first instance but pass the second set of command line parameters to it.
In this case, why not host a WCF service in your WPF application with an appropriate method which is what you pass these parameters to instead. The web page that is utilizing the ClickOnce then just calls this service method with the parameters it would have passed.

Testing WCF Service that Uses Impersonation

I am converting some existing integration tests of a legacy WCF service to be automated via NUnit. The current tests call a deployed version of the WCF service; what I would like to do is have the tests hit the service class (MyService.svc.cs) directly/internally.
The problem I am having is that the service uses impersonation:
//this is a method in MyService.svc.cs
public SomeObject GetSomeObject()
{
using (GetWindowsIdentity().Impersonate())
{
//do some stuff
}
return null;
}
private WindowsIdentity GetWindowsIdentity()
{
var callerWinIdentity = ServiceSecurityContext.Current.WindowsIdentity;
var cf = new ChannelFactory<IMyService>();
cf.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
return callerWinIdentity;
}
The problem is that ServiceSecurityContext.Current is always null when I call it from a unit test.
The impersonation is important in downstream operations, so I can't just bypass this code and just call what is within the using block. It might be possible to wrap my test code in WindowsIdentity.GetCurrent().Impersonate() and then call what is within the using block (bypassing MyService.svc.cs code), but this would be less than ideal, as it would not be a complete end-to-end test.
I do not need to fake different users to impersonate--I just need the runner's user context to be available in ServiceSecurityContext.Current.
Is this possible?
I'd still be interested in a better and less invasive way of doing this, but this seems to work for now.
I created a second constructor for MyService to allow the use of WindowsIdentity.GetCurrent().
private readonly bool _useLocalIdentity;
public MyService(bool useLocalIdentity) :this()
{
_useLocalIdentity = useLocalIdentity;
}
private WindowsIdentity GetWindowsIdentity()
{
if (_useLocalIdentity)
{
return WindowsIdentity.GetCurrent();
}
var callerWinIdentity = ServiceSecurityContext.Current.WindowsIdentity;
if (callerWinIdentity == null)
{
throw new InvalidOperationException("Caller not authenticated");
}
var cf = new ChannelFactory<IMyService>();
cf.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
return callerWinIdentity;
}

WCF Proxy usage

This answer was posted in response to this question.
It's a little above my head right now, but is the "higher order function" supposed to be used within a client proxy class? Is this correct usage?:
public class MyProxy
{
readonly IMyService service =
new ChannelFactory<IMyService>("IMyService").CreateChannel();
public ResponseObject Foo(RequestObject request)
{
return UseService((IMyService service) =>
service.Bar(request));
}
T UseService<T>(Func<IIssueTrackerService, T> code)
{
bool error = true;
try
{
T result = code(issueTrackerChannel);
((IClientChannel)issueTrackerChannel).Close();
error = false;
return result;
}
finally
{
if (error)
{
((IClientChannel)issueTrackerChannel).Abort();
}
}
}
}
All I'm really looking for is some guidance here, and the correct way to do this.
This is actually not to bad. Perhaps you can cast to an ICommunicationObject instead, as the same code is required for your hosts as well.
The way to think about it is close is the friendly call. Please finish my call and return the proxy to the connection pool. Abort is "I don't care, shut the proxy because it's dead and also remove it from the pool because it's dead".
Depending on your code, you might want to abstract the "WCF Proxy" parts of the code from the function call parts if it's possible. That way you can unit test your application logic separately from the WCF proxy code.
You may want to look at a try {} catch (CommunicationException) so you can treat your WCF exceptions separately to an application level exception too, instead of the finally.
i.e
try
{
try
{
proxy.call();
//app logic
((ICommunicationObject)proxy).Close();
}
catch (SomeAppException)
{
//recover app exception
}
}
catch (CommunicationException)
{
((ICommunicationObject)proxy).Abort();
}

Workaround for HttpContext.HideRequestResponse being internal? Detect if HttpContext.Request is really available?

We're migrating an application to use IIS7 integrated mode. In library code that is designed to work either within the context of an HTTP request or not, we commonly have code like this:
if (HttpContext.Current != null &&
HttpContext.Current.Request != null) {
// do something with HttpContext.Current.Request
} else {
// do equivalent thing without HttpContext..
}
But in IIS7 integrated mode the check for HttpContext.Current.Request throws an exception whenever this code is called from Application_Start.
protected void Application_Start(object sender, EventArgs e)
{
SomeLibrary.DoSomethingWithHttpContextCurrentDetection();
}
Results in:
System.Web.HttpException: Request is not available in this context
How can I detect whether the request is really available without wrapping these calls in an exception handler and taking action based on whether an exception is generated or not.
Looking at HttpContext in Reflector I see it has an internal bool HideRequestResponse field but it's internal so I can only get to it with reflection and that's fragile. Is there a more official/approved way to determine if it's ok to call HttpContext.Request?
This blog post about the subject says not to use HttpContext, but how, in generic library code, can you determine if it's ok to use HttpContext?
http://mvolo.com/iis7-integrated-mode-request-is-not-available-in-this-context-exception-in-applicationstart/
I'm using the work-around mentioned there which is to use Application_BeginRequest and an initialized field to only initialize once as part of BeginRequest, but that has to be done in every calling application whereas I'd prefer to make the library code more robust and handle this situation regardless of where it's called from.
I would refactor your code to this:
if (IsRequestAvailable())
{
// do something with HttpContext.Current.Request...
}
else
{
// do equivalent thing without HttpContext...
}
public Boolean IsRequestAvailable()
{
if (HttpContext.Current == null)
return false;
try
{
if (HttpContext.Current.Request == null)
return false;
}
catch (System.Web.HttpException ex)
{
#if DEBUG
// Testing exception to a magic string not the best practice but
// it works for this demo.
if (ex.Message == "Request is not available in this context")
return false;
throw;
#else
return false;
#endif
}
return true;
}
Your question asked not to use exception handling (I assume for performance reasons) and my answer does. However, by changing your code from using "If (HttpContext.Current != null && HttpContext.Current.Request != null)" to "If (IsRequestAvailable())" you only have one place to change the code when you find an answer how not to use exception handling.
I'm afraid the answer is that you can't get what you want - Microsoft sees this case as an 'exceptional circumstance' and so it will throw an exception.
You can use reflection as you describe in your answer but you don't want to and so are limited by the API that Microsoft have provided, for better or for worse.
If you do decide to use reflection, of note is the HttpApplication.InitInternal method which is what sets the HideRequestResponse flag.
Hope that helps. I would suggest you file a report with Microsoft Connect.
You should not even use Request (or Response) in the Application_Start since application could be started without a request. So in the future your application won't even run when other parts of framework stop providing the Request object.
If you want to just hack it temporarily, you could use Reflection (if you have above-medium trust) or catching an exception (even though you don't want to) and store the result in a static variable or possibly use a static HttpContext wrapper:
Also you could use HttpRuntime.UsingIntegratedPipeline.
So the best approach is remove the dependance of your classes on HttpContext when they are being initialized or not initalize them in appstart.
What is your reasoning to use Request in the app start anyway? For statistics? Or just telling the user he woke the application?
Edited with code to explain better:
public static class ContextWrapper
{
public static HttpRequest Request
{
get
{
HttpContext context = HttpContext.Current;
if (context == null) return null;
if (HttpRuntime.UsingIntegratedPipeline)
{
try { return context.Request; }
catch (HttpException e) { /* Consume or log e*/ return null; }
// Do not use message comparison - .NET translates messages for multi-culture environments.
}
return context.Request;
}
}
}
And in code:
if (ContextWrapper.Request != null) //...
Or a user-controlled faster way:
public static class ContextWrapper2
{
public static bool IsIis7IntegratedAppStart { get; set; }
public static HttpRequest Request
{
get
{
if (ContextWrapper2.IsIis7IntegratedAppStart) return null;
HttpContext context = HttpContext.Current;
if (context == null) return null;
return context.Request;
}
}
}
And in app start:
protected void Application_Start(object sender, EventArgs e)
{
yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = true;
//...
yourLibraryNamespace.yourClass.Init();
//...
yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = false;
}
You could note this behaviour in your documentation and all should be well. AppStart-like context should be the only place where you get such an exception.
You could also implement IDisposable on a member and use it in appStart with the using statement so you do not forget to set IsIis7IntegratedAppStart = false.
I think I have the solution for you. I maintain a logging library and have the same issue as you. If it is a web request I am grabbing some data from the HttpContext. But depending on how the logging library is used this same scenario can happen. So here is my solution. The key fix for me was checking if the Handler was null or not.
if (System.Web.Hosting.HostingEnvironment.IsHosted
&& System.Web.HttpContext.Current != null
&& System.Web.HttpContext.Current.Handler != null
&& System.Web.HttpContext.Current.Request != null)
{
//access the Request object here
}
Depending on what you are trying to accomplish, you may be able to get some of the properties and settings around the web app from System.Web.Hosting.HostingEnvironment
I added a comment, but it gets auto-hidden.
I think it's more important to have an idea of what it is that you need from the request.
For instance, the link you provided which provides a workaround is looking for Request.ApplicationPath.
If that's actually what you're looking for (for, say, loading the web.config vs the app.config), you could do this:
if (HttpRuntime.AppDomainAppId != null)
return WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath);
else
return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
If this (or HttpRuntime.ApplicationPath) isn't what you're actually looking for, it would be helpful to know which properties of the Request you are actually looking for. Maybe there's a better, safer way to get there.

To handle exception with every form or just at main

I have a question about handling exception. I have a Winform that uses a webservice proxy on each form for data retrieval and processing. Here is where I really got confused and having a long time deciding which is better.
A. For each call in the web service do a try catch to display the error message and allow the user to re try the process by clicking the button again.
B. Since the error occurred on the web-service and the error was probably because the web service was inaccessible, just make a generic try catch in the WinMain function in the Program.cs and show an error message that web service is inaccessible before the application closes.
The main argument in this is A is more user friendly but needs a lot of try catch code. B is easier to code but just lets the application ends. I am leaning on A but am trying to search the net with options how to lessen the code needed to be written to do this. Any ideas there?
When you add a web reference, the code generator automatically adds "Async" methods to access the web service.
I would recommend that you use the Async methods rather than the synchronous methods. The nice thing about that is that the EventArgs for the Async methods provide an Error property that you can use to see if the request was successful or not.
private void CheckWebservice(string data)
{
WebService.Server server = new WebService.server();
server.methodCompleted += server_methodCompleted;
server.methodAsync(data);
}
private void server_methodCompleted(object sender, methodCompletedEventArgs e)
{
if (e.Error != null)
if (MessageBox.Show("Error", "Error", MessageBoxButtons.AbortRetryIgore) == DialogResult.Retry)
{
// call method to retry
}
else
{
if (e.Result == "OK") { // Great! }
}
}
If you must use the synchronous methods for some reason, then you could, of course, write a class to encapsulate the methods to call your web service so that you can call it from various places without duplicating the code. Your encapsulation class could do all the error handling and return a result.
class CallWebService
{
public enum Result
{ Unknown, Success, NotAvailable, InvalidData } // etc
public Call(string data)
{
Webservice.Server server = new Webservice.Server();
string result = string.Empty;
try
{
result = server.getResult(data);
}
catch (Exception ex) // replace with appropriate exception class
{
return Result.NotAvailable;
}
if (result == "OK") return Result.Success
else return Result.InvalidData;
}
}
Encapsulate the webservice call and the try/catch block inside a class =)

Categories

Resources