RestSharp for PCL not returning data from ASP.NET Web API - rest

I use this sample tutorial to create a simple Web API.
Then I downloaded the PCL version of RestSharp from here, compiled and tried to execute this test code:
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var client = new RestClient("http://localhost:18506/api/");
var request = new RestRequest("products", Method.GET);
client.ExecuteAsync<List<Product>>(request, response =>
{
foreach (var a in response.Data)
{
Console.WriteLine(a.Name);
}
});
}
public class Product
{
public string Name { get; set; }
}
}
Nothing is being written to the console and if I put a break point within the call back, it is not hit.
Any suggestions?
TIA.

You've triggered an asynchronous HTTP call and never seem to be waiting for it to complete. Try waiting or your unit test might finish much before the Web API is even hit by the request:
client.ExecuteAsync<List<Product>>(request, response =>
{
...
}).Result;
But in a unit test you probably don't need to be complicated your life with asynchronous HTTP calls. Just use a standard synchronous call and assert on the results received.

Related

Blazor Server - DbContext is disposed after refreshing page

I am developing a Blazor server app, where all clients will have a list of things, any one of these clients can update thing which should then trigger a callback telling all clients to call DbContext.Entry(thing).Reload() so they're up to date. This works all great and well until I refresh the page, then I get the Cannot access a disposed object error and I can't figure out how to get around it.
I have the follow services:
services.AddDbContextPool<MainDbContext>(...);
services.AddSingleton<RefreshService>();
RefreshService.cs:
public class RefreshService {
public Func<long, Task> OnRefreshThing { get; set; }
public void RefreshThing(long thingId) => OnRefreshThing?.Invoke(thingId);
}
Index.blazor:
protected override void OnInitialized() {
RefreshService.OnRefreshIssue += OnRefreshIssue;
}
private async Task OnRefreshThing(long thingId) {
// This works perfectly until I refresh the page & try to call it again
Thing thing = await MainDbContext.Things.FindAsync(thingId); // exception is thrown here
await MainDbContext.Entry(thing).ReloadAsync();
}
And here's an example of what triggers the error:
Thing thing = Things.Where(t => t.ThingId == 1);
thing.Name = "New name";
RefreshService.RefreshThing(thing.ThingId);
You can modify the RefreshService to be Scoped not Singleton
The AddDbContextPool does not dispose the instance of the dbcontext completely, it resets the instance to its default state and it could be because of the reset that it can't access it again

Using UnityWebRequest to get response body in a static class

Our WebGL game made using Unity requires getting data from the body of a GET response. Currently this is implemented using a static class, with a blocking while loop to wait for the request to be done:
public static class NetworkController {
public MyDataClass GetData() {
UnityWebRequest webRequest = UnityWebRequest.Get(...);
webRequest.SendWebRequest();
while (!webRequest.isDone) {} // block here
// Get body of response webRequest.downloadHandler.text and
// return a MyDataClass object
}
}
This works in the editor until later we discovered using WebGL disallows blocking the web request. Unity suggests using coroutines to mitigate that, but StartCoroutine() only exists in the MonoBehaviour class which our static class cannot inherit from.
Is there a way to continue the execution only after the web request gets a response while using a static class?
As per comments, the code is modified so now the static class makes a call to a MonoBehaviour singleton:
public static class NetworkController {
public MyDataClass GetData() {
return NetworkControllerHelper.GetInstance().GetData();
}
}
public class NetworkControllerHelper : MonoBehaviour {
/* ... GetInstance() method for creating a GameObject and create & return an instance... */
private MyDataClass coroutineResult = null;
public MyDataClass GetData() {
UnityWebRequest webRequest = UnityWebRequest.Get(...);
StartCoroutine(WebRequestCoroutine(webRequest));
// How do I detect that the coroutine has ended then continue without hanging the program?
while (coroutineResult == null) {}
return coroutineResult;
}
// Coroutine for trying to get a MyDataClass object
private IEnumerator WebRequestCoroutine(UnityWebRequest webRequest) {
yield return webRequest.SendWebRequest();
while (!webRequest.isDone) yield return new WaitForSeconds(0.1f);
// Creating the MyDataClassObject
coroutineResult = ...;
yield break;
}
}
We need to wait for the resulting MyDataClass to be created, so we check if coroutineResult is null, but using a while loop to block hangs the program. How do I wait for a some seconds before checking for the loop condition?
You can't load a resource synchronously in WebGL as explained here.
Do not block on WWW or WebRequest downloads
Do not use code which blocks on a WWW or WebRequest download, like this:
while(!www.isDone) {}
Although, I cannot find a proper solution, I need 'webRequest.downloadHandler.text' and I want to use this string globally on another classes.

When using MockRestServiceServer cannot precisely test number of service calls

I am coding some retry logic for a service call, and attempting to test that the Rest Template is attempting to hit the service a certain number of times, in a unit test. I am using the following code to perform the test.
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(ExpectedCount.times(5), method(HttpMethod.GET))
.andRespond(withServerError());
service.call();
I have the retry logic set to only make two attempts. The above test code requires that it occur five times, but the test always passes. In fact, the only way I can get this test to fail is by setting the expected count to one (anything less than the number of actual invocations). The same sort of problem occurs when I use ExpectedCount.min or ExpectedCount.between in that the test will only fail when actual invocations exceed expectation.
I need to be able to test for an exact number of service calls, preferably without the use of Mockito.
This is what finally worked for me, testing with a max attempts of 4:
MockRestServiceServer server;
#Before
public void setUp() {
server = MockRestServiceServer.bindTo(restTemplate).build();
}
#After
public void serverVerify() {
server.verify();
}
#Test
public void doWork_retryThenSuccess() throws Exception {
final String responseBody = "<some valid response JSON>";
final String url = BASE_URL + "/doWork";
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new SocketTimeoutException("first")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new IOException("second")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(ExceptionResponseCreator.withException(new RemoteAccessException("third")));
server.expect(requestTo(url))
.andExpect(MockRestRequestMatchers.method(HttpMethod.POST))
.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));
final MyResponseClass response = myService.call();
assertThat(response, notNullValue());
// other asserts here...
}
We are constrained to use Spring Test 5.0.10, which doesn't have MockRequestResponseCreators.withException() (method was added in 5.2.2). Borrowing from Spring 5.2.7 code, this works well:
package com.company.test;
import java.io.IOException;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.test.web.client.ResponseCreator;
import org.springframework.test.web.client.response.MockRestResponseCreators;
public class ExceptionResponseCreator extends MockRestResponseCreators {
public static ResponseCreator withException(IOException ex) {
return request -> { throw ex; };
}
public static ResponseCreator withException(RemoteAccessException ex) {
return request -> { throw ex; };
}
}
You can create your own ResponseCreator with the logic you want. For example:
class DelegateResponseCreator implements ResponseCreator {
private final ResponseCreator[] delegates;
private int toExecute = 0;
public DelegateResponseCreator(final ResponseCreator... delegates) {
this.delegates = delegates;
}
#Override
public ClientHttpResponse createResponse(final ClientHttpRequest request) throws IOException {
ClientHttpResponse ret = this.delegates[this.toExecute % this.delegates.length].createResponse(request);
this.toExecute++;
return ret;
}
}
This delegator executes the ResponseDelegates in order.
So you can mock the response for the call number you want
mockServer.expect(ExpectedCount.times(5), MockRestRequestMatchers.method(HttpMethod.GET))
.andRespond(new DelegateResponseCreator(
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withServerError(),
MockRestResponseCreators.withSuccess()
));
In this example, the first four calls will return a server error whereas the fifth will be a success.
You need to call mockServer.verify() after making all your requests to check if the expectations are met. Otherwise, you can get away with never making any requests.

ASP.NET Core 2: Entity Framework Context is disposed too early in asynchronous PayPal IPN. How do I get it back in a later thread?

I have an endpoint which is receiving IPN activity from PayPal. Here is the POST Action that is taken straight from their docs with manual modifications:
[HttpPost]
public IActionResult Receive()
{
IPNContext ipnContext = new IPNContext()
{
IPNRequest = Request
};
using (StreamReader reader = new StreamReader(ipnContext.IPNRequest.Body, Encoding.ASCII))
{
ipnContext.RequestBody = reader.ReadToEnd();
}
List<KeyValuePair<string, string>> ipnVarsWithCmd = ipnContext.RequestBody.Split('&')
.Select(x => new KeyValuePair<string, string>(x.Split('=')[0], x.Split('=')[1])).ToList();
//Fire and forget verification task -- ** THIS **
Task.Run(() => VerifyTask(ipnContext, ipnVarsWithCmd));
//Reply back a 200 code
return Ok();
}
The issue is the indicated line. This is a "fire and forget" route, and is executed asynchronously. When the Action is complete, and returns Ok, I am assuming that the injected Entity Framework context from the controller:
public class IPNController : Controller
{
private readonly EFContext _context;
public IPNController(EFContext context)
{
_context = context;
}
}
... gets Disposed? According to my logs, it looks like it.
Meanwhile, I have that second thread doing the actual legwork of the IPN request which needs that EFContext to be around.
Is there a pattern I am missing here? (Bearing in mind whilst I'm not new to .NET I am to .NET Core)
Or is there a way I can "get it back" so I can use it?
Update:
You might find my initialisation of the context useful:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<EFContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}
Change:
Task.Run(() => VerifyTask(ipnContext, ipnVarsWithCmd));
to
await Task.Run(() => VerifyTask(ipnContext, ipnVarsWithCmd));
and method declaration to:
public async Task<IActionResult> Receive()
Also wrap IPNContext to using block to let it dispose when it is not needed.

Why are my WCF Async with Rx unit tests unstable?

I am using Rx and RxUI in a MVVM project and have a view model that queries its data from a WCF service asynchronously. In the unit tests I create a mock object that returns a Task with the expected value.
Here's a general idea of what my view model looks like
public class ViewModel : ReactiveObject
{
private IContext _context;
public ViewModel(IContext context)
{
_context = context;
Observable.FromAsync(() => _context.WcfServiceCall())
.Subscribe(result => {
Children.AddRange(results.Select(r => new ChildViewModel(r).ToList()));
});
}
public ObservableCollection<ChildViewModel> { get; private set;}
}
My unit test looks like this
[TestFixture]
public class ViewModelTest : AssertionHelper
{
[Test]
public void ShouldSetChildren()
{
var c = new Mock<IContext>();
c.Setup(q => q.WcfServiceCall())
.Returns(Task.Run(() => new []{ 1,2,3,4,5,6 })):
var vm = new ViewModel(c.Object);
var p = vm.Children.First(); // this call sometimes fails
...
}
}
The issue I'm having is that I have over 400 tests that do this sort of thing and they all work most of the time but I randomly get failed tests, one or two at a time, that report the sequence has no values. This is unpredictable and random. I can run the tests again after a failure and all succeed. I have added the TestScheduler as described here but the problems persist.
Is there a better way to test methods that make asynchronous method calls?
Edit from Paul Bett's input:
I see FromAsync does not take an IScheduler parameter but I do have SubscribeOn and ObserveOn available.
Alternatively, I could call the WCF async method directly and convert the returned Task to an observable. I'm not sure I understand when it is more appropriate to use Observable.FromAsync versus not using it.
Does Observable.FromAsync take an IScheduler parameter? Is it your Test Scheduler?
I realize that my unit tests were incorrect in that they were touching too many moving parts. I have tests that verify that the mocked web service calls are being made when expected and I really shouldn't include that complexity in tests that aren't focused on that test point.
I'm calling the wcf service when navigating to the view model. Here's a better representation of my view model with minor changes regarding specifying an IScheduler:
public class ViewModel : ReactiveObject, IRoutableViewModel
{
private IContext _context;
public ViewModel(IContext context)
{
_context = context;
Weeks = new ReactiveCollection<WeekViewModel>();
this.WhenNavigatedTo(() =>
{
_context.Service.GetWeeksAsync()
.ToObservable()
.ObserveOn(RxApp.DeferredScheduler)
.Subscribe(result =>
{
Weeks.AddRange(result.Select(w => WeekViewModel(w)));
});
});
// ...
}
public ReactiveCollection<WeekViewModel> Weeks { get; private set; }
}
Instead of setting up the context to populate the Weeks collection then using the router to navigate to the ViewModel I am now adding objects to the Weeks collection in the unit tests and skipping navigation and the asynchronous web service calls. This has reduced the tests a bit, eliminated the instability as far as I can tell, and reduced the execution time of test suite.
So my unit tests look something like this
[TestFixture]
public class ViewModelTest : AssertionHelper
{
[Test]
public void ShouldSetChildren()
{
var c = new Mock<IContext>();
var vm = new ViewModel(c.Object);
vm.Children.AddRange((new []{1,2,3,4,5,6}).Select(i => new ChildViewModel(i)));
var p = vm.Children.First(); // this is valid now - no timing issues
...
}
}
The code behaves correctly in the app but was problematic in the test runner so I believe that this solves my immediate issues.