stub webserver for integration testing - c#

I have some integration tests where I want to verify certain requires are made against a third-[arty webserver. I was thinking I would replace the third-party server with a stub server that simply logs calls made to it. The calls do not need to succeed, but I do need a record of the requests made (mainly just the path+querystring).
I was considering just using IIS for this. I could 1) set up an empty site, 2) modify the system's host file to redirect requests to that site 3) parse the log file at the end of each test.
This is problematic as for IIS the log files are not written to immediately, and the files are written to continuosly. I'll need to locate the file, read the contents before the test, wait a nondeterministic amount of time after the test, read the update contents, etc.
Can someone think of a simpler way?

You could use the System.Net.HttpListener ( MSDN LINK ).
It works as embedded WebServer, this means you can even check the access on-the-fly without having to parse log files.
A class i used in my Code recently:
class Listener
{
private HttpListener listener = null;
public event EventHandler CommandReceived;
public Listener()
{
this.listener = new HttpListener();
this.listener.Prefixes.Add("http://localhost:12345/");
}
public void ContextReceived(IAsyncResult result)
{
if (!this.listener.IsListening)
{
return;
}
HttpListenerContext context = this.listener.EndGetContext(result);
this.listener.BeginGetContext(this.ContextReceived, this.listener);
if (context != null)
{
EventHandler handler = this.CommandReceived;
handler(context, new EventArgs());
}
}
public void Start()
{
this.listener.Start();
this.listener.BeginGetContext(this.ContextReceived, this.listener);
}
public void Stop()
{
this.listener.Stop();
}
}

Yeah, I don't think you need a whole webserver. You don't need to test HTTP.
What you do need to test is the underlying data structure that you're sending and receiving. So just create tests for that (i.e. make a point at which you can validate your generate dataformat with what is expected, and also with what you intend to receive, etc).
Test the data, not the protocol (unless, obviously, the protocol is custom).

I've done something very similar to this in a number of projects.
You don't want to create stubbed web service. That's just adding a dependency you don't need. What I did was create an interface which mimics the web service's API. I then created a proxy class that will call the web service in the live system. For testing I used RhinoMocks to create mocked classes that return the results I wanted to test for. This was very useful for me, as I could then produce all sorts of 'unexpected' behaviour which wouldn't be possible with the live system.
public interface IServiceFacade {
string Assignments();
}
public class ServiceFacade : IServiceFacade {
private readonly Service _service;
public ServiceFacade(Service service) {
_service = service;
}
public string Assignments() {
return _service.Assignments();
}
}
Then my test code contained stuff like this:
var serviceFacade = MockRepository.GenerateMock<IServiceFacade>();
serviceFacade.Stub(sf => sf.Assignments()).Return("BLAH BLAH BLAH");
or
serviceFacade.Stub(sf => sf.Assignments()).Return(null);
or
serviceFacade.Stub(sf => sf.Assignments()).Throw(new Exception("Some exception"));
I found this very useful.

Related

How to initialize Singleton with its dependencies?

I am trying to Force the immediate instantiation or a Singleton in .Net 6. The reason I want to do this is because I want to load some data the moment that the application starts. I don't know if my approach is correct and if it is possible. Suggestions are more than welcome.
This is what I have tried so far.
My program.cs configuration
builder.Services.AddScoped<IIpLocationService, IpLocationService>();
var serviceProvider = builder.Services.BuildServiceProvider();
var memoryCacheProvider = new MemoryCacheProvider(
serviceProvider.CreateScope().ServiceProvider
.GetService<IIpLocationService>());
builder.Services.AddSingleton<IMemoryCacheProvider>(memoryCacheProvider)
But I get this error.
System.InvalidOperationException: 'Unable to resolve service for type 'Auth.In_MemoryDatabase.IMemoryCacheProvider' while attempting to activate 'Auth.Services.IpLocationService'.'
IIpLocationService has its own dependencies too. Namely a unitofwork in charge of retrieving the information from a database and the MemoryCacheProvider class to store the information in-memory.
This is my code of the MemoryCacheProvider
public interface IMemoryCacheProvider
{
List<IpLocation> IpLocationList { get; set; }
}
public class MemoryCacheProvider : IMemoryCacheProvider
{
private readonly IIpLocationService _ipLocationService;
public List<IpLocation> IpLocationList { get; set; } = new List<IpLocation>();
public MemoryCacheProvider(IIpLocationService ipLocationService)
{
_ipLocationService = ipLocationService;
Init();
}
private void Init()
{
// do something with it
_ipLocationService.Init();
}
}
Is there a way I can make this work or something similar? I just need the data to start loading the moment the application starts because it's a lot of data. For this reason, I must be able to call the Init method of the IpLocationService.
I am not quite sure what you are trying to accomplish
Is there a way I can make this work or something similar? I just need the data to start loading the moment the application starts because it's a lot of data. For this reason, I must be able to call the Init method of the IpLocationService.
Maybe you can take a look in a Hosted service (IHostedService). This code will run before requests can be received. This way you can inject your dependancies in the hosted service, and fetch fetch your data.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio#startasync
Alternatively, you can run it in your Program.cs
You can get your services after building the Host, but before you run it.
var host = CreateHostBuilder(args).Build();
host.Services.GetRequiredService<...>(...);
host.Run();
I hope this gives you some ideas on how to solve your issue.

How to call a method of the ServiceHost from the hosting process in WCF C#

I have a publisher / subscriber pattern WCF Duplex ServiceHost that is hosted by a Windows Service. The Windows Service receives events from a separate process. OnEvent I would like to force my WCF Host to publish that data to all subscribed clients. Typically if a Client is calling this is straight forward. But when my Service Host needs to do this - I can't get my head around HOW to do that.
I have 2 questions:
1: I do not know how to create a Channel in WCFHost from my Windows Service so that it can use to publish to the Subscribers.
2: I read Creating WCF ChannelFactory so I do know I am creating a DuplexChannelFactory (2 per second ) which might be too much overhead.
Any help examples, hints are greatly appreciated. I am not a WCF expert and currently know more about it than I thought I should have to know in order to use it.
I had read on SO
Can I call a Method in a self hosted wcf host locally?
So then I have created a method inside my WCFHost like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
I get an error of course that there is no InstanceContext because I am constructing using typeof(Cback) ..
"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."
So I am not sure how I can go about performing this ?
And for those that say read the error : yes I read the error.
Now how to do that with an InstanceContext that does not exist as OperationContext.Current does not exist at this point as I am calling this method form my Hosting Process into my WCFHost.
So if I could have a nice example of how to do this - even if I must use the code example on the 2nd link (of course implementing the DuplexChannelFactory) I would greatly appreciate it.
EDIT
Basically the windows Service is doing some heavy work monitoring other services, about 2 times a second it then must publish that to "Subscribed" Clients via WCF.
I think you have got very confused about how everything is wired together and are mixing concepts from the client in with the service. You haven't provided much concrete information about your scenario to go on so I'm going to provide a small example and hopefully you will be able to apply the ideas to your problem.
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
In your OnEvent method, you would call something similar to this inside your event method.
MyService.SendDataToClients(mydata);
This uses static data to store the list of clients. If you wanted to do something like segment your clients for different endpoints, you would need to do something different. There is a potential out of order message and scaling problem with this code if your OnEvent method can be called again while the previous call hasn't completed. For example, if you receive 2 messages, the first being large and the second being small, you could potentially send the second smaller message to clients later in the HashSet iteration order before they have been sent the first message. Also this won't scaled to a large number of clients as you could block timing out on one client holding up messages being sent to other clients. You could use something similar to Task's to dispatch multiple message deliveries. If this needs to scale, I would suggest looking at Reactive Extensions for .Net

How to reconfigure SQLTransport based NServicebus in Asp.net Web API?

I am using NServicebus(version 4.6.3) with SQLTransport in my ASP.net web api project. I have different connectionstrings for the queues for different environments (Dev,QA,etc). My configuration looks like below:
public class BusConfigurator
{
public static IStartableBus Bus { get; private set; }
public static void DisposeBus()
{
if (Bus == null)
return;
Bus.Shutdown();
Bus.Dispose();
Bus = null;
}
public static void InitializeServiceBus(string connectionString)
{
var configure = Configure.With()
.DefineEndpointName("MyEndPoint")
.Log4Net(new DebugAppender { Threshold = Level.Warn })
.UseTransport<SqlServer>(connectionString)
.PurgeOnStartup(false)
.SetDefaultTransactionLevel()
.UnicastBus(); // Error is thrown here on second call
configure.MyCustomSQLServerPersistence();
Bus = configure.CreateBus();
}
public static void StartBus()
{
Bus.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
I have a dropdown in the app so that the user can select the environment. Based on the selection, I want to reconfigure the bus. So, I call DisposeBus then pass the connection string to the IntializeServiceBus method followed by the startBus. It works first time but throws error below when it gets called again with different connectionstring:
Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Source=NServiceBus.Core
Line=0
BareMessage=Unable to set the value for key: NServiceBus.Transport.ConnectionString. The settings has been locked for modifications. Please move any configuration code earlier in the configuration pipeline
Is NServicebus intended to be used/configured this way? (I am guessing probably not) If not then is there a workaround/different approach for this?
In V4 or below, there is no way to do it by normal human means. There is only one Bus per AppDomain. All of the configuration API is static, so if you try, you get exactly the problems you ran into.
By "human means", I mean that it might be possible to do something crazy with spinning up a new AppDomain within your process, setting up a Bus within that, and then tearing it down when you're finished. It might be possible. I haven't tried it. I wouldn't recommend it.
In V5, the configuration API is completely redesigned, is not static, and so this is possible:
var cfg = new BusConfiguration();
// Set up all the settings with the new V5 Configuration API
using (var justOneBus = NServiceBus.Bus.Create(cfg).Start())
{
// Use justOneBus, then it gets disposed when done.
}
That's right. It's disposable. Then you can do it again. In your case you wouldn't want to put it in a using block - you would want to set it up somewhere, and when the dropdown gets switched, call Dispose on the current instance and rebuild it with the new parameters.
Keep in mind, however, that the Bus is still pretty expensive to create. It's definitely still something you want to treat as an application-wide singleton (or singleton-like) instance. You definitely wouldn't want to spin up a separate one per web request.

Add unit test case to test external webservice (.asmx) .NET

I have made a code to read the external web service and find the expose methods and their parameters using System.Web.Services.ServiceDescription.
I am also able to invoke the method and get the output through webservice.
This is done only on the bases of external Web service Url.
Everything is done from CodeBehind (C#).
I need to add the unit test case to test the functionality by adding dummy .asmx webservice which will be accessed by unit test.
Please let me know or have suggestion to how can i create a dummy service on the fly and used.
As far as I can see, there 2 different functionalists:
WSDL provider - i.e. class which gets a valid wsdl from somewhere
WSDL parser - the class which parses the wsdl and extracts the data
Here is a pseudo-code implementation of these to make them easy to mock and unit test.
public interface IWSDLProvider
{
string GetWsdlFromService(string url);
}
public class MyWsdlProvider : IWSDLProvider
{
private readonly IWebWrapper _webCLient;
public MyWsdlProvider(IwebWrapper webClient)
{
_webClient = webCLient;
}
public string GetWsdlFromService(string url)
{
//do here whatever is needed with the webClient to get the wsdl
}
}
public interface IWSDLParser
{
MyServiceData GetServiceDataFromUrl(string url);
}
public class MyWsdlParser : IWSDLParser
{
private readonly IWSDLProvider _wsdlProvider;
public MyWsdlParser(IWSDLProvider wsdlProvider)
{
_wsdlProvider = wsdlProvider;
}
public MyServiceData GetServiceDataFromUrl(string url)
{
//use the wsdl provder to fetch the wsdl
//and then parse it
}
}
The IWebClient is a wrapper around WebClient to allow easy mocking.
Using any mocking framework with the above code, you can easily isolate and mock any part, and test only the behavior at hand. That way, you can even make the mock for the wsdl provider to return any wsdl you want to test with.
You can go even further and wrap/isolate the System.Web.Services.ServiceDescription calls, so you don't really have to pass even a wsdl in your tests, just work on the results.

Analyze the use of a ASP.NET webservice

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.

Categories