How to Assert for Response Code for request using flurl - flurl

I was trying to put an assert for Response Code for my request, but i am having hard time to figure out, could you please help me on this. Here is my implementation and definition.
myTests.cs
var accessToken = await helper.SendRequestAsync<AccessToken>(baseUrl, body);
==> how to set assert here right after above statement to verify response status?
helpers.cs
public static async Task<T> SendRequestAsync<T>(string baseUrl, Dictionary<string, string> body)
{
using (var flurl_client = new FlurlClient(baseurl))
{
try
{
var response = await flurl_client
.Request()
.PostUrlEncodedAsync(body)
.ReceiveJson<T>();
return response;
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
return default(T);
}
}
======================================================
Data model for "AccessToken" is in Dto.cs
public class AccessToken
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string ext_expires_in { get; set; }
public string expires_on { get; set; }
public string not_before { get; set; }
public string resource { get; set; }
public string access_token { get; set; }
public string refresh_token { get; set; }
public object Status_Code { get; set; }
}

If you're you looking for Flurl's testing features to help with this, I'm afraid it won't work. Those features are specifically designed for testing the behavior of your client-side code based on fake responses that you set up in your test. It looks like you want to assert the status code from a real call.
The best way I can think of is to drop the .ReceiveJson<T>() line in SendRequestAsync and change the method signature to return Task<HttpResponseMessage>:
using System.Net.Http;
public static async Task<HttpResponseMessage> SendRequestAsync(string baseUrl, Dictionary<string, string> body)
{
using (var flurl_client = new FlurlClient(baseurl))
{
try
{
var response = await flurl_client
.Request()
.PostUrlEncodedAsync(body); // this returns Task<HttpResponseMessage>
return response;
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
return null;
}
}
Then your test can do this:
var resp = await Helper.SendRequestAsync(...);
Assert.AreEqual(HttpStatusCode.OK, resp.StatusCode);
Anything that needs the deserialized response body can do this:
var token = await Helper.SendRequestAsync(...).ReceiveJson<AccessToken>();

Related

How to Model Object upload in API with form-data in asp.net Web Api

Model Class:
public class TestAspDotNetModelClass
{
public int Id { get; set; }
public string Name { get; set; }
public byte[] file { get; set; }
}
API Controller Action:
public class ValuesController: ApiController
{
[System.Web.Http.HttpPost]
public HttpResponseMessage PostComplex(TestAspDotNetModelClass update)
{
if (update.fileProfile != null)
{
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
File and value post in postman
object post in API but API message show this error
You Can handle the situation with two scenario.
You can use HttpContext.Current.Request
Not required as you mentioned in model class byte[] property.
Ref. Link 1 : https://www.c-sharpcorner.com/UploadFile/2b481f/uploading-a-file-in-Asp-Net-web-api/
public class ValuesController: ApiController
{
[System.Web.Http.HttpPost]
public HttpResponseMessage PostComplex(TestAspDotNetModelClass update)
{
if (update.fileProfile != null)
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
You can go with same as you mentioned byte[] that is not possible to create json thats why you can convert byte[] to Base64String then it is possible.
Ref. Link 2 : Saving a base64 string as an image into a folder on server using C# and Web Api
Model Class
public class TestAspDotNetModelClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Base64Stringfile { get; set; }
}
API Controller Action
public class ValuesController: ApiController
{
[System.Web.Http.HttpPost]
public HttpResponseMessage PostComplex(TestAspDotNetModelClass update)
{
if (update.Base64Stringfile != null)
{
// Convert base 64 string to byte[]
byte[] fileBytes = Convert.FromBase64String(update.Base64Stringfile);
// Convert your byte[] to file
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}

Debugger Stops while Parsing Rest API response HttpClient, Xamarin Forms

I am trying to parse response from ASP.NET Core Web API. I am able to parse the response JSON into C# object successfully but app crashes without throwing any error when the parsed C# object is returned to the ViewModel.
in ViewModel
ApiResponse response = await _apiManager.GetAsync<ApiResponse>("authentication/GetUserById/1");
Response JSON:
{
"result": {
"id": 1,
"userType": 1,
"firstName": “FirstName”,
"middleName": null,
"lastName": “LastName”,
},
"httpStatusCode": 200,
"httpStatusDescription": "200OkResponse",
"success": true,
"message": "hello"
}
HttpClient GetAsync() method:
public async Task<TResult> GetAsync<TResult>(string endpoint)
{
HttpResponseMessage httpResponse = _httpClient.GetAsync(endpoint).GetAwaiter().GetResult();
httpResponse.EnsureSuccessStatusCode();
TResult t = default(TResult);
if (httpResponse.IsSuccessStatusCode)
{
string serialized = await httpResponse.Content.ReadAsStringAsync();
t = JsonConvert.DeserializeObject<TResult>(serialized);
}
return t;
}
App crashes (debugger stops without any error) at "return t" statement. Here, _httpClient is a singleton object of HttpClient using DI.
TResult model is ApiResponse object
public class User
{
[JsonProperty("id")]
public int UserId { get; set; }
[JsonProperty("userType")]
public int UserType { get; set; }
[JsonProperty("firstName")]
public string FirstName { get; set; }
[JsonProperty("middleName")]
public string MiddleName { get; set; }
[JsonProperty("lastName")]
public string LastName { get; set; }
}
public abstract class ResponseBase
{
[JsonProperty("httpStatusCode")]
public int HttpStatusCode { get; protected set; }
[JsonProperty("httpStatusDescription")]
public string HttpStatusDescription { get; protected set; }
[JsonProperty("success")]
public bool Success { get; protected set; }
[JsonProperty("message")]
public string Message { get; protected set; }
}
public class ApiResponse : ResponseBase
{
[JsonProperty("result")]
public User Result { get; set; } = new User();
}
There are two issues:
1. when the following statement executes, app crashes and debugger stops without throwing any error.
HttpResponseMessage httpResponse = await _httpClient.GetAsync(endpoint).ConfigureAwait(false);
But when GetAsync() is called with .GetAwaiter().GetResult(), network call is placed successfully. I do not understand why ConfigureAwait(false) fails.
HttpResponseMessage httpResponse = _httpClient.GetAsync(endpoint).GetAwaiter().GetResult();
why the following call fails and app crashes? How can I return parsed C# object to the calling code?
return JsonConvert.DeserializeObject(serialized);
Please advise.
Try this
try
{
var result = await httpClient.GetAsync(endpoint);
var response = await result.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<TResult>(response);
}
catch (Exception exp)
{
Console.Write(exp.InnerMessage);
}
Make sure that you have installed Newtonsoft.Json

SignalR missing connection in HubCallerContext

Trying to do simple chat and sending user to the userTracker when he/she is connected
public override async Task OnConnectedAsync()
{
var user = Helper.GetUserInformationFromContext(Context);
await this.userTracker.AddUserAsync(Context.Connection, user);
await Clients.All.SendAsync("UsersJoined", new UserInformation[] { user });
await Clients.All.SendAsync("SetUsersOnline", await GetOnlineUsersAsync());
await base.OnConnectedAsync();
}
but in the old versions HubCallerContext is like this :
public HubCallerContext(HubConnectionContext connection);
public HubConnectionContext Connection { get; }
public ClaimsPrincipal User { get; }
public string ConnectionId { get; }
the version I am using ( 2.3.0 ) is like
protected HubCallerContext();
public abstract string ConnectionId { get; }
public abstract string UserIdentifier { get; }
public abstract ClaimsPrincipal User { get; }
public abstract IFeatureCollection Features { get; }
public abstract CancellationToken ConnectionAborted { get; }
public abstract void Abort();
So how can I get the missing Connection ?
You simple have to inject it where you use it
Sample:
public class YourClassWhereYouNeedHubContext
{
// Inject into constructor
public YourClassWhereYouNeedHubContext (IHubContext<VarDesignHub> hubcontext)
{
HubContext = hubcontext;
...
}
private IHubContext<VarDesignHub> HubContext
{
get;
set;
}
}
Then you can also call
await this.HubContext.Clients.All.InvokeAsync("Completed", id);
Please read also:
Call SignalR Core Hub method from Controller

GCM request in Asp.net

I have reffered this link for sending GCM request and it is working perfectly fine. gcm-push-notification-with-asp-net
I referred one more link to post JSON how-to-post-json-to-the-server
On the basis of second link I have tried the following code.
var httprequest = (HttpWebRequest)WebRequest.Create("https://gcm-http.googleapis.com/gcm/send");
httprequest.ContentType = "application/json";
httprequest.Method = "POST";
httprequest.Headers.Add(string.Format("Authorization: key={0}", GCM.APIKey));
httprequest.Headers.Add(string.Format("Sender: id={0}", GCM.ProjectNo));
using (var streamWriter = new StreamWriter(httprequest.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(new GCMValues
{
delay_while_idle = false,
priority = "high",
registration_id = regId,
data = new MessagesValues
{
message = message
}
});
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httprequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Properties that I have used
public class GCMValues
{
public Object data { get; set; }
public bool delay_while_idle { get; set; }
public String priority { get; set; }
public String registration_id { get; set; }
}
public class MessagesValues
{
public String message { get; set; }
public DateTime? time { get; set; }
}
The problem I am facing is at line var httpResponse =(HttpWebResponse)httprequest.GetResponse();
I am getting a response of bad request.
Where I went wrong or what could be done to pass the values in JSON format for GCM post request.
Thanks in advance.
You need registration_ids (plural) not registration_id (singular) in the JSON. It is an array of strings , not a single string value.
If you check the GCM documentation it gives all the JSON options.
Elsewhere the documentation details how to use to if you have just one token to send a notification to, as in this example:
{
"to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "myicon"
}
}
I have used the following way to get it done, and it worked.
var httprequest = (HttpWebRequest)WebRequest.Create("https://gcm-http.googleapis.com/gcm/send");
httprequest.ContentType = "application/json";
httprequest.Method = "POST";
httprequest.Headers.Add(string.Format("Authorization: key={0}", GCM.APIKey));
httprequest.Headers.Add(string.Format("Sender: id={0}", GCM.ProjectNo));
String[] regid = regId.Split(',');
using (var streamWriter = new StreamWriter(httprequest.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(new GCMValues
{
delay_while_idle = false,
priority = "high",
registration_ids = regid,
data = new MessagesValues
{
message = message
}
});
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httprequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
if (result.Contains("Error"))
{
return false;
}
}
Properties that I have used
public class GCMValues
{
public Object data { get; set; }
public bool delay_while_idle { get; set; }
public String priority { get; set; }
public String[] registration_ids { get; set; }
}
public class MessagesValues
{
public String message { get; set; }
public DateTime? time { get; set; }
}

HTTP POST to Many to Many relation using ASP.NET Web API

I am new to ASP.net (and programming in general) and I'm having trouble building a Web API. More specifically I need help in these two areas:
How to configure my DOCcontroller to post a new document (DOC table).
How to make the actual ajax post -- I am having trouble passing the EXT_GUID parameter. As it stands I get an error when I try to post. "Can't bind multiple parameters (doc and parentOwner) to the request's content."
Essentially this is for a simple document management system. I want Get/Post documents (DOC) by having the user supply an GUID from an external database (the EXT_GUID field) as a filter/parameter. Each document can have multiple EXT_GUIDs and each EXT_GUID can have multiple Documents (DOC). You can assume that the EXT_GUID fields we be populated prior to the http post.
This is the DOCcontroller code
//POST api/DOC
public HttpResponseMessage PostDOC(DOC doc, List<string> parentOwners)
{
if (ModelState.IsValid)
{
var parents = db.BIMs.Where(bx => parentOwners.Contains(bx.EXT_GUID));
foreach (var p in parents)
doc.Owners.Add(p);
db.DOCs.Add(doc);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, doc);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = doc.Id }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
This is my model setup -- EntityFramework codefirst stuff
public class EXT
{
public int Id { get; set; }
public string EXT_GUID { get; set; }
public int ProjectID { get; set; }
public virtual ICollection<DOC> DOCs { get; set; }
}
public class DOC
{
public int Id { get; set; }
public int ProjectID { get; set; }
public string Subject { get; set; }
public string Link { get; set; }
public virtual ICollection<EXT> EXTs { get; set; }
}
This is more Storage Model...
public StoreDBContext() : base("name=StoreDBContext")
{
}
public DbSet<EXT> EXTs { get; set; }
public DbSet<DOC> DOCs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set FLUENT API config for many to many here
modelBuilder.Entity<EXT>()
.HasMany(a => a.DOCs)
.WithMany()
.Map(x =>
{
x.MapLeftKey("EXT_Id");
x.MapRightKey("DOC_Id");
x.ToTable("EXTsDOCs");
});
}
AJAX Code
function AddDOC() {
var parentOwner = "{\"" + $('#txtaddEXT').val() + "\"}";
jQuery.support.cors = true;
var DOC = {
ProjectId: ProjectID,
Subject: $('#txtaddDOCSubject').val(),
Link: $('#txtaddDOCLink').val(),
parentOwner: parentOwner
};
$.ajax({
url: "http://localhost:54171/api/DOC/",
type: 'POST',
data: JSON.stringify(DOC),
contentType: "application/json;charset=utf-8",
success: function (data) {
WriteResponse(data);
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
}
What you receive from the client and what you will save in the database is two different things.
Your doc object is ok:
var DOC = {
ProjectId: ProjectID,
Subject: $('#txtaddDOCSubject').val(),
Link: $('#txtaddDOCLink').val(),
parentOwner: parentOwner
};
Now you need to change the server logic. Make a model like this:
public class DocReceivedModel
{
public int ProjectID { get; set; }
public string Subject { get; set; }
public string Link { get; set; }
public List<string> parentOwner { get; set; }
}
Then your PostDOC method will be:
public HttpResponseMessage PostDOC(DocReceivedModel docReceived)
{
if (ModelState.IsValid)
{
Doc newDoc = new Doc();
newDoc.ProjectID = docReceived.ProjectID
newDoc.Subject = docReceived.Subject
newDoc.Link = docReceived.Link
var parents = db.BIMs.Where(bx => docReceived.parentOwners.Contains(bx.EXT_GUID));
foreach (var p in parents)
newDoc.Owners.Add(p);
// I not see in your model Owners, maybe this is EXTs but I suppose you catch the idea
db.DOCs.Add(newDoc);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, newDoc);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new {id = newDoc.Id}));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}

Resources