Throw exception and getting it in assert of xunit in .net - exception

I want to test this method
public async Task<GetLayoutResponse> Handle(GetLayoutQuery request, CancellationToken cancellationToken)
{
string ravenId = UserLayout.GetId(_userService.CustomerIsin);
var cRepository = CacheableRepository<UserLayout>.From(_repository);
var res = await cRepository.GetAsync(ravenId);
if (!res.IsSucceeded)
throw new EasyException(EasyException.DATABASE_EXCEPTION, "DatabaseException");
return new GetLayoutResponse { LayoutModel=res?.Data?.LayoutModel };
}
As you can see in this part throw new EasyException(EasyException.DATABASE_EXCEPTION, "DatabaseException"); I throw an exception .
So here is my test code :
[Fact]
public async void GetLayoutQueryTestException()
{
//Arrange
var data = new domain.Entities.UserLayout() { CreateDateTime=DateTime.Now, Id= $"{nameof(UserLayout)}/", LayoutModel="MyLayout" };
var mediator = new Mock<IMediator>();
var userservice = new Mock<ICurrentUserService>();
var repoacc = new Mock<IRepositoryAccessor>();
var repo = new Mock<domain.Interfaces.IRepository<UserLayout>>();
repoacc.Setup(i => i.GetRepository<UserLayout>(It.IsAny<string>(), It.IsAny<DatabaseType>(), It.IsAny<Type>(), It.IsAny<bool>(), It.IsAny<bool>())).Returns(repo.Object);
repo.Setup(i => i.GetByIdAsync(It.IsAny<string>())).Returns(Task.FromResult(OperationResult<UserLayout>.Failed(EasyException.DATABASE_EXCEPTION.ToString())));
GetLayoutQuery command = new GetLayoutQuery();
GetLayoutQueryHandler handler = new GetLayoutQueryHandler(userservice.Object, repoacc.Object);
//Act
var x = await handler.Handle(command, new System.Threading.CancellationToken());
//Assert
Assert.IsType<EasyException>(x);
}
But my test code can't detect the exception and returns this error:
 easy.api.tests.LayoutTests.LayoutResponseTests.GetLayoutQueryTestException
 Source: LayoutResponseTests.cs line 89
 Duration: 272 ms
Message: 
domain.Exceptions.EasyException : DatabaseException
Stack Trace: 
GetLayoutQueryHandler.Handle(GetLayoutQuery request, CancellationToken cancellationToken) line 33
LayoutResponseTests.GetLayoutQueryTestException() line 109
<>c.<ThrowAsync>b__127_0(Object state)

Finally :
var caughtException =await Assert.ThrowsAsync<EasyException>(() => handler.Handle(command, new System.Threading.CancellationToken()));
Assert.Equal("DatabaseException", caughtException.Message);

Related

Asp.Net core Web API: how can I export and import JSON from the external REST APIs?

ASP.Net Core WebAPI is being built to fetch JSON from external REST API endpoint. I would like to save the JSON and reload it
At present, I am fetching the JSON from an external REST API endpoint using the following code:
public async Task<List<Weather>> Get(string cities)
{
List<Weather> weathers = new List<Weather>();
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
foreach (var city in cities.Split(";"))
{
string APIURL = $"?key={this.apiKey}&q={city}";
var response = await _httpClient.GetAsync(APIURL);
if (response.IsSuccessStatusCode)
{
var responses = await response.Content.ReadAsStreamAsync();
var weather = await JsonSerializer.DeserializeAsync<Weather>(responses, options);
weathers.Add(weather);
}
}
return weathers;
}
that returns the following JSON
[
{
"location":{
"name":"Chennai",
"region":"Tamil Nadu",
...
},
"current":{
"last_updated_epoch":1663601400,
"last_updated":"2022-09-19 21:00",
...
}
},
{
"location":{
"name":"Mumbai",
"region":"Maharashtra",
..
},
"current":{
"last_updated_epoch":1663602300,
"last_updated":"2022-09-19 21:15",
..
}
}
]
How can I export and import JSON ?
Update: I have updated the code as mentioned below
public static class JsonFileUtils
{
private static readonly JsonSerializerSettings _options
= new() { NullValueHandling = NullValueHandling.Ignore };
public static void StreamWrite(object obj, string fileName)
{
using var streamWriter = File.CreateText(fileName);
using var jsonWriter = new JsonTextWriter(streamWriter);
JsonSerializer.CreateDefault(_options).Serialize(jsonWriter, obj);
}
public static async Task StreamWriteAsync(object obj, string fileName)
{
await Task.Run(() => StreamWrite(obj, fileName));
}
}
and used it like
public async Task<List<Weather>> Get(string cities)
{
List<Weather> weathers = new List<Weather>();
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
foreach (var city in cities.Split(";"))
{
string APIURL = $"?key={this.apiKey}&q={city}";
var response = await _httpClient.GetAsync(APIURL);
if (response.IsSuccessStatusCode)
{
var responses = await response.Content.ReadAsStreamAsync();
var weather = await JsonSerializer.DeserializeAsync<Weather>(responses, options);
weathers.Add(weather);
}
}
var fileName = "weathers.json";
await JsonFileUtils.StreamWriteAsync(weathers, fileName);
return weathers;
}
to upload the file
[HttpPost("upload", Name = "upload")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<Weather>))]
[ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UploadFile(
IFormFile file,
CancellationToken cancellationToken)
{
string fileContent = null;
using (var reader = new StreamReader(file.OpenReadStream()))
{
fileContent = reader.ReadToEnd();
}
var result = JsonConvert.DeserializeObject<List<Weather>>(fileContent);
return Ok(result);
}

POST data to web service HttpWebRequest Windows Phone 8

I've been trying without success today to adapt this example to POST data instead of the example GET that is provided.
http://blogs.msdn.com/b/andy_wigley/archive/2013/02/07/async-and-await-for-http-networking-on-windows-phone.aspx
I've replaced the line:
request.Method = HttpMethod.Get;
With
request.Method = HttpMethod.Post;
But can find no Method that will allow me to stream in the content I wish to POST.
This HttpWebRequest seems a lot cleaner than other ways e.g. sending delegate functions to handle the response.
In Mr Wigley's example code I can see POST so it must be possible
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
I wrote this class some time ago
public class JsonSend<I, O>
{
bool _parseOutput;
bool _throwExceptionOnFailure;
public JsonSend()
: this(true,true)
{
}
public JsonSend(bool parseOutput, bool throwExceptionOnFailure)
{
_parseOutput = parseOutput;
_throwExceptionOnFailure = throwExceptionOnFailure;
}
public async Task<O> DoPostRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"post",
DateTime.Now.Ticks
));
string serialized = JsonConvert.SerializeObject(input);
StringContent stringContent = new StringContent(
serialized,
Encoding.UTF8,
"application/json");
var response = client.PostAsync(uri, stringContent);
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with POST ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
public async Task<O> DoPutRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"put",
DateTime.Now.Ticks
));
string serializedObject = JsonConvert.SerializeObject(input);
var response = client.PutAsync(uri,
new StringContent(
serializedObject,
Encoding.UTF8,
"application/json"));
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with PUT ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
}
Then when I want to call it, I can use it as following :
JsonSend<User, RegistrationReceived> register = new JsonSend<User, RegistrationReceived>();
RegistrationReceived responseUser = await register.DoPostRequest("http://myurl", user);

How to return an Error from a generic method

The title doesn't describe the issue very well so let me explain my problem.
I have a generic function to consume API's via HTTP GET calls. Which looks like this:
public async static Task<T> GetAsync<T>(string Base_Url,string relative_URL, Utility.UriExtensions.NameValueCollection Params, Utility.UriExtensions.NameValueCollection headers = null)
{
Uri CompleteURL = new Uri(Base_Url + relative_URL, UriKind.Absolute);
if (Params != null)
CompleteURL = Utility.UriExtensions.CreateUriWithQuery(CompleteURL, Params);
if(headers!=null)
{
foreach(KeyValuePair<string,string> k in headers)
{
if (ApiHttpClient.DefaultRequestHeaders.ContainsKey(k.Key))
ApiHttpClient.DefaultRequestHeaders[k.Key] = k.Value;
else
ApiHttpClient.DefaultRequestHeaders.Add(k.Key, k.Value);
}
}
Debug.WriteLine("GET : " + CompleteURL);
using (var response = await ApiHttpClient.GetAsync(CompleteURL).AsTask(cancellationToken.Token).ConfigureAwait(false))
{
string responseData="";
if (response.IsSuccessStatusCode)
{
responseData = await response.Content.ReadAsStringAsync();
Debug.WriteLine(responseData);
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.DateParseHandling = DateParseHandling.DateTime;
settings.DefaultValueHandling = DefaultValueHandling.Populate;
settings.NullValueHandling = NullValueHandling.Include;
settings.TypeNameHandling = TypeNameHandling.None;
}
try
{
response.EnsureSuccessStatusCode();
return JsonConvert.DeserializeObject<T>(responseData);
}
catch
{
// Error
Debug.WriteLine(
"Error occurred, the status code is: {0} and Content : {1}",
response.StatusCode, response.Content);
}
return default(T);
}
}
In case of error, the error is handled inside catch body. I want to return these Error informations like StatusCode and Content of response when this happens. But I am unable to make any changes to this generic function. How should handle this.
For this purpose you can use out parameter, which you will pass in your method:
public async static Task<T> GetAsync<T>(string Base_Url,string relative_URL, Utility.UriExtensions.NameValueCollection Params, Utility.UriExtensions.NameValueCollection headers = null, out StatusCode code)
StatusCode statusCode;
GetAsync<Foo>(..., out statusCode);

best overloaded method match for `RestSharp.Deserialize<RootObject>(RestSharp.IRestResponse)' has some invalid arguments

So i am working this project on Xamarin forms, and get the error as in title on
var rootObject = deserial.Deserialize<RootObject>(gameJson);
I am supposed to return the list of games to my app.How can i remove the error?
public async Task<Game[]> GetGamesAsync(){
var client = new RestClient("http://mystore/");
var request = new RestRequest ("api/Games", Method.GET);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var apiKey = session ["ApiKey"];
var userId = session ["UserId"];
try
{
request.AddHeader ("authenticationkey",apiKey.ToString ());
request.AddHeader ("authenticationid",userId.ToString ());
}
catch{}
IRestResponse response = client.Execute (request);
statusCodeCheck (response);
var gameJson = response.Content;
if (response.StatusCode == HttpStatusCode.OK) {
RestSharp.Deserializers.JsonDeserializer deserial = new RestSharp.Deserializers.JsonDeserializer ();
var rootObject = deserial.Deserialize<RootObject>(gameJson);
return rootObject.games;
}
else if(response.StatusCode == HttpStatusCode.Forbidden){
return null;
}
}
Not sure you are looking for this but I also using Restsharp in portable library and I'm deserializing datacontracts with Json.NET's JsonConvert.DeserializeObject<T>
method. I have not encountered any problem with it yet.
Also another possible solution is that the returned data is wrapped and the main object is not the RootObject.

Nancy OnError will not accept a Response object?

The Nancy documentation seems to say that Pipelines.OnError should return null - as opposed to BeforeResponse which allows both null and a Response object.
All the examples like this one and many code samples here on StackOverflow show a Response being returned in the OnError, just like in the BeforeRequest.
When I attempt to return an HTTPStatus string for the Pipelines.OnError, everything works OK!
But when I attempt to return a Response, I get a compiler error:
Operator '+=' cannot be applied to operands of type 'Nancy.ErrorPipeline' and 'lambda expression'
I'm emulating almost exactly the code in the Nancy example, except for the fact that mine is a TinyIocContainer while the example's is using a StructureMap container and a StructureMap derived bootstrapper
Here's my code:
const string errKey = "My proj error";
const string creationProblem = "Message creation (HTTP-POST)";
const string retrievalProblem = "Message retrieval (HTTP-GET)";
public void Initialize(IPipelines pipelines)
{
string jsonContentType = "application/json";
byte[] jsonFailedCreate = toJsonByteArray(creationProblem);
byte[] jsonFailedRetrieve = toJsonByteArray(retrievalProblem);
Response responseFailedCreate = new Response
{
StatusCode = HttpStatusCode.NotModified,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedCreate, 0, jsonFailedCreate.Length)
};
Response responseFailedRetrieve = new Response
{
StatusCode = HttpStatusCode.NotFound,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedRetrieve, 0, jsonFailedRetrieve.Length)
};
// POST - error in Create call
pipelines.OnError += (context, exception) =>
{
// POST - error during Create call
if (context.Request.Method == "POST")
return responsefailedCreate;
// GET - error during Retrieve call
else if (context.Request.Method == "GET")
return responseFailedRetrieve;
// All other cases - not supported
else
return HttpStatusCode.InternalServerError;
};
}
private byte[] toJsonByteArray(string plainString)
{
string jsonString = new JObject { { errKey, plainString } }.ToString();
byte[] result = Encoding.UTF8.GetBytes(jsonString);
return result;
}
I had the same problem and I found a nice approach to the problem: http://paulstovell.com/blog/consistent-error-handling-with-nancy.
you should override RequestStartup on the Bootstrapper, here my test code:
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
pipelines.OnError.AddItemToEndOfPipeline((ctx, ex) =>
{
DefaultJsonSerializer serializer = new DefaultJsonSerializer();
Response error = new JsonResponse(ex.Message,serializer);
error.StatusCode = HttpStatusCode.InternalServerError;
return error;
});
base.RequestStartup(container, pipelines, context);
}