How to mock OperationContext.Current (WCF Message) - c#

Currently I have a challenge to unit test a production code. We have a function to retrieve an IP address from an incoming WCF messages.
public void DoSomething(){
var ipAddressFromMessage = GetIpFromWcfMessage();
var IpAddress = IPAddress.Parse(ipAddressFromMessage);
if(IpAddress.IsLoopback)
{
// do something
}
else
{
// do something else
}
}
private string GetIpFromWcfMessage()
{
OperationContext context = OperationContext.Current;
string ip = ...//use the IP from context.IncomingMessageProperties to extract the ip
return ip;
}
The question is, what should I do so that I could test the checking of the IP in the DoSomething()?
[Test]
Public void DoSomethingTest()
{
//Arrange...
// Mock OperationContext so that we can manipulate the ip address in the message
// Assert.
...
}
Should I change the way I use the Operation context in a way so that I can mock it(e.g. implement an interface and mock the implementation of the interface)?

I would wrap the call with a static helper:
public static class MessagePropertiesHelper
{
private static Func<MessageProperties> _current = () => OperationContext.Current.IncomingMessageProperties;
public static MessageProperties Current
{
get { return _current(); }
}
public static void SwitchCurrent(Func<MessageProperties> messageProperties)
{
_current = messageProperties;
}
}
Then in GetIpFromWcfMessage I would call:
private string GetIpFromWcfMessage()
{
var props = MessagePropertiesHelper.Current;
string ip = ...//use the IP from MessageProperties to extract the ip
return ip;
}
And I would be able to switch the implementation in the test scenario:
[Test]
Public void DoSomethingTest()
{
//Arrange...
// Mock MessageProperties so that we can manipulate the ip address in the message
MessagePropertiesHelper.SwitchCurrent(() => new MessageProperties());
// Assert.
...
}
Here you can find my answer to similar problem: https://stackoverflow.com/a/27159831/2131067.

Related

Unable to use logger for task

I have a situation where there is a synchronous call to a method and based on a parameter we switch the response for sync /async and inside async we start a task as below. The problem is tracer works until its outside the Task() but not inside. Is it happening that Task cannot access the parent thread data ?
RequestProcessor.cs file code:
public classA_Res GetListbyUserRequest(ApiRequest<object> request)
{
if(request.IsAsync)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call started"); // this works/ gets logged in db
var taskProcessEventsResponseAsync = new Task(() =>
ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId));
taskProcessEventsResponseAsync.Start();
}
else
{
response=DataManager.Instance.GetListbyUserRequest(); // this gets paginated data for UI
}
//some code for response that request has been put down for export async.
}
private void ProcessResponseAsync(validatedInputs, options, grids, userInfo, traceRequest, exportAs, userRequestId, sessionId)
{
LocalTracer.TraceInformation(AVEventType.Info, "Async call in progress"); // this doesnt works/ doesnt gets logged in db but also doesnt throws any error
//some code for processing data in chunks and creating files on server
}
LocalTracer.cs
public interface ILocalTracer
{
void TraceInformation(AVEventType eventType, DummyParameter dummy = null);
}
public sealed class LocalTracer:ILocalTracer
{
static ILocalTracer _instance = new LocalTracer();
public static ILocalTracer Instance
{
get { return _instance; }
set { _instance = value; }
}
private LocalTracer()
{
}
public static void TraceInformation(AVEventType eventType, string sMessage = "", string
userName = "", string ipAddress = "",.....)
{
//tracer code
}
public void TraceInformation(AVEventType eventType, DummyParameter dummy = null)
{
TraceInformation(eventType, "");
}
}
Please assume all this code in proper try catch blocks.

Testing different IP addresses locally

I am implementing some code where I use a visitors IP address to determine their location. For .net core 2, this is:
var ipAddress = Request.HttpContext.Connection.RemoteIpAddress;
But of course when I test locally I always get the loop back address ::1. Is there a way to simulate external IP addresses while testing locally?
You can create a service for retrieving remote address. Define an interface for it and create 2 implementations and inject them depending on the current environment
public interface IRemoteIpService
{
IPAddress GetRemoteIpAddress();
}
public class RemoteIpService : IRemoteIpService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public RemoteIpService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public IPAddress GetRemoteIpAddress()
{
return _httpContextAccessor.HttpContext.Connection.RemoteIpAddress;
}
}
public class DummyRemoteIpService : IRemoteIpService
{
public IPAddress GetRemoteIpAddress()
{
//add your implementation
return IPAddress.Parse("120.1.1.99");
}
}
Startup
if (HostingEnvironment.IsProduction())
{
services.AddScoped<IRemoteIpService, RemoteIpService>();
}
else
{
services.AddScoped<IRemoteIpService, DummyRemoteIpService>();
}
Usage
public class TestController : Controller
{
//...
private readonly IRemoteIpService _remoteIpService;
public TestController(IRemoteIpService remoteIpService)
{
//...
_remoteIpService = remoteIpService;
}
//..
[HttpGet]
public IActionResult Test()
{
var ip = _remoteIpService.GetRemoteIpAddress();
return Json(ip.ToString());
}
}
For getting external ip for localhost, you need to send request to retrive the ip, and you could implement an extension for ConnectionInfo like
public static class ConnectionExtension
{
public static IPAddress RemotePublicIpAddress(this ConnectionInfo connection)
{
if (!IPAddress.IsLoopback(connection.RemoteIpAddress))
{
return connection.RemoteIpAddress;
}
else
{
string externalip = new WebClient().DownloadString("http://icanhazip.com").Replace("\n","");
return IPAddress.Parse(externalip);
}
}
}
And use like
var ip = Request.HttpContext.Connection.RemotePublicIpAddress();

Authorize application service based on client IP address

We have implemented some Application Service methods without any permission. How can we implement authorization based on client IP address for executing methods?
For example, this is GetParsedData method:
public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
return _cacheManager.GetCache(nameof(GetData)).Get(input.ToString(), () => gpd(input)) as GetParsedDataOutput;
}
How can we check user permission by IP address? Suppose that client with IP address 192.168.5.2 is granted permission to execute this method.
You can inject IClientInfoProvider to get ClientIpAddress.
Authorize an authenticated user
Override IsGrantedAsync in PermissionChecker:
public override async Task<bool> IsGrantedAsync(long userId, string permissionName)
{
if (permissionName == MyClientIpAddressPermissionName)
{
return Task.Run(() => { return _clientInfoProvider.ClientIpAddress == "192.168.5.2"; });
}
return await base.IsGrantedAsync(userId, permissionName);
}
Usage:
[AbpAuthorize(MyClientIpAddressPermissionName)]
public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
// ...
}
Authorize an anonymous user
Since AbpAuthorize requires a user, you should use a custom (i) attribute, (ii) interceptor, and (iii) interceptor registrar.
(i) Attribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ClientIpAuthorizeAttribute : Attribute
{
public string AllowedIpAddress { get; set; }
}
(ii) Interceptor:
internal class ClientIpAuthorizationInterceptor : IInterceptor
{
private readonly IClientInfoProvider _clientInfoProvider;
public ClientIpAuthorizationInterceptor(IClientInfoProvider clientInfoProvider)
{
_clientInfoProvider = clientInfoProvider;
}
public void Intercept(IInvocation invocation)
{
var methodInfo = invocation.MethodInvocationTarget;
var clientIpAuthorizeAttribute = methodInfo.GetCustomAttributes(true).OfType<ClientIpAuthorizeAttribute>().FirstOrDefault()
?? methodInfo.DeclaringType.GetCustomAttributes(true).OfType<ClientIpAuthorizeAttribute>().FirstOrDefault();
if (clientIpAuthorizeAttribute != null &&
clientIpAuthorizeAttribute.AllowedIpAddress != _clientInfoProvider.ClientIpAddress)
{
throw new AbpAuthorizationException();
}
invocation.Proceed();
}
}
(iii) Interceptor registrar:
internal static class ClientIpAuthorizationInterceptorRegistrar
{
public static void Initialize(IIocManager iocManager)
{
iocManager.IocContainer.Kernel.ComponentRegistered += (key, handler) =>
{
if (ShouldIntercept(handler.ComponentModel.Implementation))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(ClientIpAuthorizationInterceptor)));
}
};
}
private static bool ShouldIntercept(Type type)
{
if (type.GetTypeInfo().IsDefined(typeof(ClientIpAuthorizeAttribute), true))
{
return true;
}
if (type.GetMethods().Any(m => m.IsDefined(typeof(ClientIpAuthorizeAttribute), true)))
{
return true;
}
return false;
}
}
Initialize the registrar in your Application module:
public override void PreInitialize()
{
ClientIpAuthorizationInterceptorRegistrar.Initialize(IocManager);
}
Usage:
[ClientIpAuthorize(AllowedIpAddress = "192.168.5.2")]
public GetParsedDataOutput GetParsedData(GetParsedDataInput input)
{
// ...
}
You should be able to extend that yourself to allow/disallow multiple IP addresses.
To fallback on permission names for an authenticated user, add the permission name as a string property in the attribute. Then inject IAbpSession and IPermissionChecker in the interceptor to call the IsGrantedAsync method.
You can write your own injector service for IApplicationService. And just before the application service method executes, you can make pre-checks.
See how to implement the injection
https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection

Testing self message send in Akka.NET

I am new in Akka.NET, at moment I am having difficulty in test if my actor sent any message to himself.
This is my actor code:
public class MySuperActor : ReceiveActor
{
private readonly IActorRef _anotherActor;
public RoteadorDeContratosSuspensoActor(IActorRef anotherActor)
{
_anotherActor = anotherActor;
Receive<MySuperActorMessage>(m => HandleMessage(m));
Receive<MySuperActorSuperMessage>(m => HandleSuperMessage(m));
}
private void HandleMessage(MySuperActorMessage message)
{
Self.Tell(new MySuperActorSuperMessage(message));
}
private void HandleSuperMessage(MySuperActorSuperMessage message)
{
_anotherActor.Tell(new AnotherActorMessage(message));
}
}
And that is my test code
[TestFixture]
public class MySuperActorTest : TestKit
{
private IActorRef _sut;
private IActorFactory _actorFactory;
private List<Contrato> _contratos;
private Props _props;
[Test]
public void WhenReceiveASimpleMessageActorShouldSendSuperMessageToHimself()
{
var testProbe = CreateTestProbe();
Props props = Props.Create<MySuperActor>(testProbe);
var sut = ActorOf(_props);
sut.Tell(new MySuperActorMessage());
ExpectMsg<MySuperActorSuperMessage>();
}
}
My test always break with the following message:
Failed: Timeout 00:00:03 while waiting for a message of type AkkaNetTestPlaygroung.MySuperActorSuperMessage
How can I check if my actor is sending another message to himself?
Alberto.
Actually, calling ExpectMsg() in your test method would expect a message to be sent back to your test actor system (I mean a context, on which initial MySuperActorMessage was sent), but not to MySuperActor instance. It would be better (and more correct) to expect AnotherActorMessage instance on your test probe, that you create in your test.
Here is a test method that pass:
[Test]
public void WhenReceiveASimpleMessageActorShouldSendSuperMessageToHimself()
{
var testProbe = this.CreateTestProbe();
var props = Props.Create<MySuperActor>(testProbe);
var sut = this.Sys.ActorOf(props);
sut.Tell(new MySuperActorMessage());
testProbe.ExpectMsg<AnotherActorMessage>();
}

How do I resolve an IP Adress from a host name on windows phone 8.1?

How do I write a method that resolves the hostname which is entered as a parameter that returns an IP Address?
I searched for a way to do this and both of the sites I found have similar solutions
WP7 Mango - How to get an IP address for a given hostname
https://social.msdn.microsoft.com/Forums/en-US/5c07b344-be5b-4358-beb1-abea581ca2bb/how-to-resolve-a-hostname-to-an-ip-address-in-windows-phone-8?forum=wpdevelop
public void DnsLookup(string hostname)
{
var endpoint = new DnsEndPoint(hostname, 0);
DeviceNetworkInformation.ResolveHostNameAsync(endpoint, OnNameResolved, null);
}
private void OnNameResolved(NameResolutionResult result)
{
IPEndPoint[] endpoints = result.IPEndPoints;
// Do something with your endpoints
}
I am having trouble using the soluitons.
I can't change the return type of the OnNameResolved and the ResolveHostNameAsync requires a NameResolutionCallback.
So how do I make a method that returns the IP Adress?
Given the limited capabilities by the .NET Framework here, you have to write an asynchronous approach here:
public static class NetworkHelper
{
public event EventHandler<DnsLookupCompletedEventArgs> DnsLookupCompleted;
public void DnsLookupAsync(string hostname)
{
var endpoint = new DnsEndPoint(hostname, 0);
DeviceNetworkInformation.ResolveHostNameAsync(endpoint, OnNameResolved, null);
}
private void OnNameResolved(NameResolutionResult result)
{
IPEndPoint[] endpoints = result.IPEndPoints;
var args = new DnsLookupCompletedEventArgs(endpoints);
if (DnsLookupCompleted != null)
DnsLookupCompleted(this, args);
}
}
Whereas DnsLookupCompletedEventArgs would look like this, so you can handle the endpoints later on:
public class DnsLookupCompletedEventArgs : EventArgs
{
public IPEndPoint[] Endpoints { get; private set; }
public DnsLookupCompletedEventArgs(IPEndPoint[] endpoints)
{
Endpoints = endpoints;
}
}

Categories