Passing a message back with response code via class - c#

I am using a web api but I want to be able to pass back a message with my response but I am using this method outside in a class how would one do that in the example of the following.
public HttpStatusCode CreateInvoice(string PumpName,string customerCode, double fuelQty, double price)
{
HttpStatusCode retval = new HttpStatusCode();
SAPbobsCOM.Documents oInvoice = company.GetBusinessObject(BoObjectTypes.oInvoices);
oInvoice.DocDate = DateTime.Now;
oInvoice.CardCode = customerCode;
oInvoice.Lines.ItemCode = "DSL";
oInvoice.Lines.Quantity = fuelQty;
oInvoice.Lines.LineTotal = price;
oInvoice.Lines.Add();
int addInvoice = oInvoice.Add();
if (addInvoice == 0)
{
retval = HttpStatusCode.OK;
}
if (addInvoice < 0)
{
string errorDescription = company.GetLastErrorDescription();
retval = HttpStatusCode.NotModified;
}
return retval;
}
I want to be able to pass back this line as part of the response message I no how to do it in the controller but this function is outside in a class. As there I dont have access to the request object?
string errorDescription = company.GetLastErrorDescription();
Edit 2
Ok so I created the function with httprequest message but i am not seeing the result in the header its showing me status 200 ok for invoice created but not the message.
public HttpResponseMessage CreateInvoice(string PumpName,string customerCode, double fuelQty, double price,string FuelType)
{
HttpResponseMessage retval = new HttpResponseMessage();
SAPbobsCOM.Documents oInvoice = company.GetBusinessObject(BoObjectTypes.oInvoices);
HttpRequestMessage Errordescription = new HttpRequestMessage() ;
oInvoice.DocDate = DateTime.Now;
oInvoice.CardCode = customerCode;
oInvoice.Lines.ItemCode = FuelType;
oInvoice.Lines.Quantity = fuelQty;
oInvoice.Lines.LineTotal = price;
oInvoice.Lines.Add();
int addInvoice = oInvoice.Add();
if (addInvoice == 0)
{
retval.StatusCode = HttpStatusCode.OK;
retval.RequestMessage=new HttpRequestMessage(HttpMethod.Post, "Invoice has been created!");
}
if (addInvoice < 0)
{
retval.StatusCode = HttpStatusCode.NotAcceptable;
retval.RequestMessage = new HttpRequestMessage(HttpMethod.Post,string.Format("Invoice was not created {0} sap code error {1}!", company.GetLastErrorDescription(),addInvoice));
}
HttpResponseMessage response = retval;
return response;
}
Here is how I consume the message in my API Controller.
public HttpResponseMessage Post(string PumpName, string FuelTagNumber,
double FuelQty, double FuelValue, string FuelType, string TransactionDate, string TransActionDate, string systemgroup1, string systemgroup2, string systemgroup3, string systemgroup4)
{
HttpResponseMessage retVal = new HttpResponseMessage();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
int connect = _boneAPi.Connect();
if (connect == 0)
{
string CustomerCode = _boneAPi.GetCustomerCodeByVechicleTag(FuelTagNumber);
HttpResponseMessage _invoiceStatusCode = _boneAPi.CreateInvoice(PumpName, CustomerCode, FuelQty, FuelValue,FuelType);
retVal = _invoiceStatusCode;
_boneAPi.ImportTransactionToTable("", CustomerCode, TransactionDate, TransactionDate, systemgroup1, systemgroup3, FuelTagNumber, systemgroup2, systemgroup4, FuelQty.ToString(), FuelValue.ToString(), FuelType, "1");
}
return retVal;
}
To show post man result
Edit 2
To Show others how I solved it.
public HttpResponseMessage CreateInvoice(string PumpName, string customerCode, double fuelQty, double price, string FuelType)
{
HttpResponseMessage retval = new HttpResponseMessage();
SAPbobsCOM.Documents oInvoice = company.GetBusinessObject(BoObjectTypes.oInvoices);
HttpRequestMessage Errordescription = new HttpRequestMessage();
oInvoice.DocDate = DateTime.Now;
oInvoice.CardCode = customerCode;
oInvoice.Lines.ItemCode = FuelType;
oInvoice.Lines.Quantity = fuelQty;
oInvoice.Lines.LineTotal = price;
oInvoice.Lines.Add();
int addInvoice = oInvoice.Add();
if (addInvoice == 0)
{
retval.StatusCode = HttpStatusCode.OK;
retval.RequestMessage = new HttpRequestMessage(HttpMethod.Post, "");
retval.Content = new StringContent("Invoice has been created!");
}
if (addInvoice < 0)
{
retval.StatusCode = HttpStatusCode.NotAcceptable;
retval.Content = new StringContent(string.Format("Invoice was not created {0} sap code error {1}!", company.GetLastErrorDescription(), addInvoice));
}
HttpResponseMessage response = retval;
return response;
}

How about making the return a Tuple
If you are using c# 7 it would look like this:
public (HttpStatusCode code, string description) CreateInvoice(string PumpName, string customerCode, double fuelQty, double price)
{
HttpStatusCode retval = new HttpStatusCode();
string errorDescription = string.Empty;
SAPbobsCOM.Documents oInvoice = company.GetBusinessObject(BoObjectTypes.oInvoices);
oInvoice.DocDate = DateTime.Now;
oInvoice.CardCode = customerCode;
oInvoice.Lines.ItemCode = "DSL";
oInvoice.Lines.Quantity = fuelQty;
oInvoice.Lines.LineTotal = price;
oInvoice.Lines.Add();
int addInvoice = oInvoice.Add();
if (addInvoice == 0)
{
retval = HttpStatusCode.OK;
}
if (addInvoice < 0)
{
errorDescription = company.GetLastErrorDescription();
retval = HttpStatusCode.NotModified;
}
return (code: retval, description: errorDescription);
}
If an older version you would need to return a Tuple<HttpStatusCode, string>

I'd strongly recommend that a function that is creating invoices shouldn't know/care about http status codes at all.
All you need to know is whether it created a new invoice or not, and if not, why not. One option is to use an exception, but if "not modified, for reason xxx" is something you expect to happen reasonably often then that's probably not the best way forward. What you arguably want is some sort of discriminated union, but C# doesn't have a nice built in way of achieving that, so you could define a "response" type that can hold either a successful response or an error description. Then in your controller layer (that does need to know about http status codes etc), determine what sort of response to return to the client based on the contents of the response object. If you'd like the response object itself to be responsible for determining whether the error message should be exposed, ít could have a method that takes two lambdas, calling either one if in 'success' state, or the other (with the error description as a parameter) in the failed state. But that's arguably overkill.

Related

Connection reset issue in .net core api call (net::ERR_CONNECTION_RESET 200 (OK))

I have a .net core API service which is called from a angular client project.
When a user request a status of his payment, we will make call to this service api and this service will then call a payment gateway service to fetch the status of payment and the output result will return to the user.
When i try to integrate this i am facing this below error.
net::ERR_CONNECTION_RESET 200 (OK)
core.js:5967 ERROR Unknown Error
This above issue is not showing when i try to hit the service after putting one breakpoint. Its also returning the result.
This is how entire flow works
Client side call performs by user
this.dataservice.postFeed(method, JSON.stringify(this.initsearch)).subscribe(result => {
var response = result.body["data"];
console.log(response);
});
Server side code looks like
[HttpPost]
public async Task<IActionResult> Post([FromBody] ObjectModel searchValue)
{
ApiResponse<string> response = new ApiResponse<string>();
IBaseResult<string> result = await _adlerBo.GetPaymentStatus(searchValue);
response.Success = result.success;
response.Data = result.Data;
return Ok(response);
}
In BusinessObject.cs
public async Task<IBaseResult<string>> GetPaymentStatus(PaymentSearchModel requestModel){
string apiResponse = await PaymentStatusCheckUsingAPI(requestModel.orderid);
return apiResponse ;
}
private async Task<string> PaymentStatusCheckUsingAPI(string orderNumber)
{
string message = await PostPaymentRequestToGateway(statusApiUrl, authQueryUrlParam);
NameValueCollection param = await GetResponseMap(message);
string status = "";
string encResJson = "";
if (param != null && param.Count == 2)
{
for (int i = 0; i < param.Count; i++)
{
if ("status".Equals(param.Keys[i]))
{
status = param[i];
}
if ("enc_response".Equals(param.Keys[i]))
{
encResJson = param[i];
}
}
if (!"".Equals(status) && status.Equals("0"))
{
resJson = crypto.Decrypt(encResJson, workingKey);
}
else if (!"".Equals(status) && status.Equals("1"))
{
Console.WriteLine("failure response: " + encResJson);
}
}
return resJson;
}
private async Task<string> PostPaymentRequestToGateway(string queryUrl, string urlParam)
{
string message = "";
try
{
StreamWriter myWriter = null;// it will open a http connection with provided url
WebRequest objRequest = WebRequest.Create(queryUrl);//send data using objxmlhttp object
objRequest.Method = "POST";
//objRequest.ContentLength = TranRequest.Length;
objRequest.ContentType = "application/x-www-form-urlencoded";//to set content type
myWriter = new System.IO.StreamWriter(objRequest.GetRequestStream());
myWriter.Write(urlParam);//send data
myWriter.Close();//closed the myWriter object
// Getting Response
System.Net.HttpWebResponse objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse();//receive the responce from objxmlhttp object
using (System.IO.StreamReader sr = new System.IO.StreamReader(objResponse.GetResponseStream()))
{
message = await sr.ReadToEndAsync();
//Response.Write(message);
}
}
catch (Exception exception)
{
Console.Write("Exception occured while connection." + exception);
}
return message;
}
private async Task<NameValueCollection> GetResponseMap(string message)
{
//await Task.Delay(2000); I did this with no Luck
NameValueCollection Params = new NameValueCollection();
if (message != null || !"".Equals(message))
{
string[] segments = message.Split('&');
foreach (string seg in segments)
{
string[] parts = seg.Split('=');
if (parts.Length > 0)
{
string Key = parts[0].Trim();
string Value = parts[1].Trim();
Params.Add(Key, Value);
}
}
}
return await Task.FromResult(Params);
}
Any idea how to fix this? Why its working when i put breakpoint and not otherwise.
Am i doing correct asynchronous implimentsion in my api?

send image with other attributes to post method in api

I use the code below to send an image to post method and save it as BLOB in DB and it's working successfully:
angular code:
public postUploadedFile(file:any){
this.formData = new FormData();
this.formData.append('file',file,file.name);
this.Url='http://localhost:38300/api/site/PostUploadFiles';
console.log("url passed from here",this.Url)
return this.http.post(this.Url , this.img).subscribe()
}
API code:
public IHttpActionResult PostUploadFiles()
{
int i = 0;
var uploadedFileNames = new List<string>();
string result = string.Empty;
HttpResponseMessage response = new HttpResponseMessage();
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
while(i < httpRequest.Files.Count && result != "Failed")
{
br = new BinaryReader(httpRequest.Files[i].InputStream);
ImageData = br.ReadBytes(httpRequest.Files[i].ContentLength);
br.Close();
if (DB_Operation_Obj.Upload_Image(ImageData) > 0)
{
result = "success";
}
else
{
result = "Failed";
}
i++;
}
}
else
{
result = "can't find images";
}
return Json(result);
}
but now I need to send more info with image ( type id, name) not just the image, so angular code will be like :
public postUploadedFile(file:any, type_id:number,site_id:number){
this.img = new Image_List();
this.img.images = new Array<PreviewURL>();
this.img.type_id= type_id;
this.img.Reference_id = site_id;
this.img.images.push(file);
this.formData = new FormData();
this.formData.append('file',file,file.name);
this.Url='http://localhost:38300/api/site/PostUploadFiles';
console.log("url passed from here",this.Url)
return this.http.post(this.Url , this.img).subscribe()
}
any help to send and insert in DB.
I think you could just make a single upload file method, and make another method for data insert with the file name,so it will be like:
public postUploadedFile(file:any){ this.formData = new FormData(); this.formData.append('file',file,file.name); this.Url='http://localhost:38300/api/site/PostUploadFiles';
This.newMethod(filename);//and here you upload the other data
console.log("url passed from here",this.Url) return this.http.post(this.Url , this.img).subscribe() }
Use FormData to append additional information to api call.
const formData = new FormData();
formData.append(file.name, file,'some-data');
You can use multiple values with the same name.

API is mixing up data from different devices

I have an API that has devices firing data to it at the same time or within a few milliseconds. What I am finding is that the data is getting mixed up. The data is sent every five minutes (on the clock 05, 10, 15 etc.) I have an execution filter that traps the URL data coming in so I always have a real source, then it goes to the endpoint and then onto processing. For example, there will a be random five minute period missing. When I debug step by step with the missing URL from the execution filter it works fine. By that I mean I take the URL and debug, then it inserts.
In summary, I have device id 1 and device id 2.I will get missing intervals even though, I can see the data has hit the execution filter.
I am assuming that the API is not handling these as separate transactions, but somehow mixing them up together, hence the data missing and the serial numbers appearing in the wrong place, such that data from id 1 is appearing in id 2 vice versa etc.
API End Point:
public class SomeController : ApiController
{
[HttpGet]
[ExecutionFilter]
public async Task<HttpResponseMessage> Get([FromUri] FixedDataModel fdm)
{
var reply = new HttpResponseMessage();
string url = HttpUtility.UrlDecode(HttpContext.Current.Request.QueryString.ToString());
if (url.Contains("timestamp"))
{
reply = TimeSyncValidation.TimeSync;
return reply;
}
else if (!url.Contains("timestamp"))
{
reply = await Task.Run(() => DeviceClass.DeviceApiAsync(fdm, url));
}
return reply;
}
}
Processing class:
namespace API.Services
{
public class DeviceClass
{
private static string serialNumber;
private static byte chk;
private static string channelName, channelReadingNumber, channelValue, queryString, readingDate;
private static int colonPosition, chanCountFrom, equalsPosition;
private static bool checkSumCorrect;
public static HttpResponseMessage DeviceApiAsync(FixedDataModel fdm, string urlQqueryString)
{
Guid guid = Guid.NewGuid();
//ExecutionTrackerHandler.Guid = guid;
//Remove question mark
var q = urlQqueryString;
queryString = q.Substring(0);
var items = HttpUtility.ParseQueryString(queryString);
serialNumber = items["se"];
//Store raw uri for fault finding
var rawUri = new List<RawUriModel>
{
new RawUriModel
{
UniqueId = guid,
RawUri = q,
TimeStamp = DateTime.Now
}
};
//Checksum validation
chk = Convert.ToByte(fdm.chk);
checkSumCorrect = CheckSumValidator.XorCheckSum(queryString, chk);
if (!checkSumCorrect)
{
return ValidationResponseMessage.ResponseHeaders("Checksum");
}
//Create list of items that exist in URL
var urldata = new UrlDataList
{
UrlData = queryString.Split('&').ToList(),
};
var data = new List<UriDataModel>();
//Split the URL string into its parts
foreach (var item in urldata.UrlData)
{
colonPosition = item.IndexOf(":");
chanCountFrom = colonPosition + 1;
equalsPosition = item.LastIndexOf("=");
if (colonPosition == -1)
{
channelName = item.Substring(0, equalsPosition);
channelReadingNumber = "";
channelValue = item.Substring(item.LastIndexOf("=") + 1);
}
else
{
channelName = item.Substring(0, colonPosition);
channelReadingNumber = item.Substring(chanCountFrom, equalsPosition - chanCountFrom);
channelValue = item.Substring(item.LastIndexOf("=") + 1);
if (channelName == "atime" || channelName == "adate")
{
readingDate = DateValidator.CreateDate(channelValue);
}
};
bool nullFlag = false;
if (channelValue == null)
nullFlag = true;
bool missingFlag = false;
if (channelValue == "x") {
missingFlag = true;
channelValue = "0";
}
//Add data to model ready for DB insert.
data.Add(new UriDataModel
{
uid = guid,
SerialNumber = serialNumber,
ChannelName = channelName,
ChannelReadingNumber = channelReadingNumber,
ChannelValue = channelValue.Replace(",", "."),
ReadingDate = readingDate,
TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm"),
Processed = false,
NullFlag = nullFlag,
MissingFlag = missingFlag
});
};
//Validate dates
var allDates = (from x in data where x.ChannelName.Contains("atime") || x.ChannelName.Contains("adate") select x.ChannelValue).ToList();
bool dateValidation = DateValidator.IsValid(allDates);
if (!dateValidation)
{
return ValidationResponseMessage.ResponseHeaders("Date");
};
//Validate values
var channels = Enum.GetNames(typeof(Channels)).ToList();
List<string> allChannelValues = data.Where(d => channels.Contains(d.ChannelName)).Select(d => d.ChannelValue).ToList();
bool valueValidation = ValueValidator.IsValid(allChannelValues);
if (!valueValidation)
{
return ValidationResponseMessage.ResponseHeaders("Values");
};
//Insert live data
var insertData = DataInsert<UriDataModel>.InsertData(data, "Staging.UriData");
if (!insertData)
{
return ValidationResponseMessage.ResponseHeaders("Sql");
}
var content = "\r\nSUCCESS\r\n";
var reply = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(content)
};
return reply;
}
}
}
TIA
You are using global variables and static method to process your data.
Change your method to non-static.
Each DeviceClass worker must update only its own isolated data then push that off back to controller.

Null Point Exception happening in the HttpClient.GetAsync methode

I'm working on a Xamarin.Forms application in which I'm downloading some data from the server and showing them on the screen. This data is downloaded every 5-10 seconds in order to keep the application updated. My code for the data download looks like this:
public async Task<List<string>> RefreshProgressPageAsync()
{
var uri = new Uri(string.Format("http://someurladdress1"));
List<string> returnValue = new List<string>();
try
{
var response = await client.GetAsync(uri);
string allResult = string.Empty;
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
string[] valuePartsArray = result.Split(',');
string id = valuePartsArray[0].Substring(valuePartsArray[0].IndexOf(':') + 1);
string name = valuePartsArray[1].Substring(valuePartsArray[1].IndexOf(':') + 1);
string value = valuePartsArray[2].Substring(valuePartsArray[2].IndexOf(':') + 1);
returnValue.Add(string.Format("{0}|{1}|{2}", id, name, value));
}
uri = new Uri(string.Format("http://someurladdress2"));
response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
string[] valuePartsArray = result.Split(',');
string id = valuePartsArray[0].Substring(valuePartsArray[0].IndexOf(':') + 1);
string name = valuePartsArray[1].Substring(valuePartsArray[1].IndexOf(':') + 1);
string value = valuePartsArray[2].Substring(valuePartsArray[2].IndexOf(':') + 1);
returnValue.Add(string.Format("{0}|{1}|{2}", id, name, value));
}
return returnValue;
}
catch (Exception ex)
{
Debug.WriteLine(#" ERROR {0}", ex.Message);
return new List<string>();
}
}
Client is the HttpClient. There are two calls for the client because I want to download two different set of data in one RefreshProgressPageAsync call.
Now my problem with this is when second await client.GetAsync(uri) happens, I get a null point exception somewhere in the GetAsynch call, which is not caught by the try-catch block. I do have a workaround by not parsing the string and instead send it as is, but my question is what could cause this NullPointException?

C# Unit tests - Unable to extract Content from the IHttpActionResult responce

I have this controller
[Route("GeocacheAddressObjectList")]
[HttpPost]
public async Task<IHttpActionResult> GeocacheAddressObjectList([FromBody] List<GeocacheAddress> addresses)
{
//check valid addresses
if(addresses == null)
{
return BadRequest("Invalid addresses. The address list object is null!") as IHttpActionResult;
}
ElasticHelper searchHelper = new ElasticHelper(ConfigurationManager.AppSettings["ElasticSearchUri"]);
List<GeocacheAddress> geocodedAddresses = new List<GeocacheAddress>();
// check each address in the addresses list against geocache db
foreach (GeocacheAddress address in addresses)
{
var elasticSearchResult = SearchGeocacheIndex(address);
// found a match
if (elasticSearchResult.Total != 0)
{
SearchProperties standardizedAddressSearch = new SearchProperties();
standardizedAddressSearch.Size = 1;
standardizedAddressSearch.From = 0;
Address elasticSearchResultAddress = elasticSearchResult.Hits.ElementAt(0).Source;
// query the standardized key in geocache db
standardizedAddressSearch.ElasticAddressId = elasticSearchResultAddress.Standardized.ToString();
// the address is already standardized, return the standardized address with its geocode
if (standardizedAddressSearch.ElasticAddressId == "00000000-0000-0000-0000-000000000000")
{
geocodedAddresses.Add(new GeocacheAddress
{
Id = address.Id,
Street = elasticSearchResultAddress.AddressString,
City = elasticSearchResultAddress.City,
State = elasticSearchResultAddress.State,
ZipCode = elasticSearchResultAddress.Zipcode,
Plus4Code = elasticSearchResultAddress.Plus4Code,
Country = elasticSearchResultAddress.Country,
Latitude = elasticSearchResultAddress.Coordinates.Lat,
Longitude = elasticSearchResultAddress.Coordinates.Lon
});
}
else // perform another query using the standardized key
{
Address standardizedAddress = StandardAddressSearch(standardizedAddressSearch).Hits.ElementAt(0).Source;
if (standardizedAddress == null)
{
return BadRequest("No standardized address found in geocache database") as IHttpActionResult;
}
geocodedAddresses.Add(new GeocacheAddress()
{
Id = address.Id,
Street = standardizedAddress.AddressString,
City = standardizedAddress.City,
State = standardizedAddress.State,
ZipCode = standardizedAddress.Zipcode,
Plus4Code = standardizedAddress.Plus4Code,
Country = standardizedAddress.Country,
Latitude = standardizedAddress.Coordinates.Lat,
Longitude = standardizedAddress.Coordinates.Lon
});
}
}
else // not found in geocache db, call SmartStreets API
{
List<Address> address_list = new List<Address>();
using (HttpClient httpClient = new HttpClient())
{
//Send the request and get the response
httpClient.BaseAddress = new System.Uri(ConfigurationManager.AppSettings["GeocodingServiceUri"]);
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
//Lookup object to perform Geocoding service call
var postBody = JsonConvert.SerializeObject(new Lookup()
{
MaxCandidates = 1,
Street = address.Street,
City = address.City,
State = address.State,
ZipCode = address.ZipCode
});
var requestContent = new StringContent(postBody, Encoding.UTF8, "application/json");
// Send the request and get the response
var response = await httpClient.PostAsync("GeocodeAddressObject", requestContent);
if (!response.IsSuccessStatusCode) //error handling
{
geocodedAddresses.Add(new GeocacheAddress()
{
Id = address.Id,
Error = response.ReasonPhrase
});
}
Geocode geocodeFromGeocoder = JsonConvert.DeserializeObject<List<Geocode>>(response.Content.ReadAsStringAsync().Result).ElementAt(0);
GeocacheAddress geocodedAddress = new GeocacheAddress()
{
Id = address.Id,
Street = geocodeFromGeocoder.CorrectedAddress,
City = geocodeFromGeocoder.City,
State = geocodeFromGeocoder.State,
ZipCode = geocodeFromGeocoder.Zipcode,
Plus4Code = geocodeFromGeocoder.Plus4Code,
Country = geocodeFromGeocoder.Country,
Latitude = geocodeFromGeocoder.Latitude,
Longitude = geocodeFromGeocoder.Longitude
};
geocodedAddresses.Add(geocodedAddress);
// check each geocoded address against geocache db
Guid standardized_key;
var geocodedAddressResult = SearchGeocacheIndex(geocodedAddress);
// found a match
if (geocodedAddressResult.Total != 0)
{
Address standardizedAddress = geocodedAddressResult.Hits.ElementAt(0).Source;
standardized_key = standardizedAddress.AddressID;
}
else // not found, insert geocode into geocache db
{
Address new_standardized_address = createStandardizedAddress(geocodeFromGeocoder);
standardized_key = new_standardized_address.AddressID;
address_list.Add(new_standardized_address);
}
// insert non-standardized address into geocache db
Address new_nonstandardized_address = createNonStandardizedAddress(address, standardized_key);
address_list.Add(new_nonstandardized_address);
}
searchHelper.BulkIndex<Address>(address_list, "xxx", "xxx");
}
}
return Json(geocodedAddresses, new Newtonsoft.Json.JsonSerializerSettings()) as IHttpActionResult;
}
I am writing a unit test to test some part of this controller.
I want to compare the response received from the controller with the expected value. When i debug the result, it shows the content for the response but I am unable to use content like (result.Content) in the code.
When i try to use this line, then it returns null response.
var result = await controller.GeocacheAddressObjectList(testGeocacheAddress) as OkNegotiatedContentResult<GeocacheAddress>;
Actual unit test code. I would appreciate any help.
[TestMethod]
public async Task TestMethod1()
{
var controller = new GeocachingController();
var testGeocacheAddress = new List<GeocacheAddress>();
testGeocacheAddress.Add(new GeocacheAddress
{
City = "Renton",
});
var result = await controller.GeocacheAddressObjectList(testGeocacheAddress);
var expected = GetGeocacheAddress();
Assert.AreEqual(result.Content.City, expected[0].City);
}
private List<GeocacheAddress> GetGeocacheAddress()
{
var testGeocacheAddress = new List<GeocacheAddress>();
testGeocacheAddress.Add(new GeocacheAddress
{
Id = Guid.Empty,
Street = "365 Renton Center Way SW",
City = "Renton",
State = "WA",
ZipCode = "98057",
Plus4Code = "2324",
Country = "USA",
Latitude = 47.47753,
Longitude = -122.21851,
Error = null
});
return testGeocacheAddress;
}
In your unit test you need to cast the result to JsonResult<T>, more specifically JsonResult<List<GeocacheAddress>> as that is what you are returning.
var result = await controller.GeocacheAddressObjectList(testGeocacheAddress) as JsonResult<List<GeocacheAddress>>;
If you were to have used return Ok(geocodedAddresses) in your controller return (where you now return the call from Json) then you could have cast to OkNegotiatedContentResult<List<GeocacheAddress>>.
Also in your Controller code you do not need to cast the return to IHttpActionResult because JsonResult<T> already implements that. The cast is redundant.
That's quite simple to achieve, all you have to do is cast the content you're expecting in your unit test method.
Example:
Controller:
public class FooController : ApiController
{
public IHttpActionResult Get()
{
var foo = "foo";
return Ok(foo);
}
}
Unit test:
[TestMethod]
public void Get_Foo_From_Controller()
{
var fooController = new FooController();
var result = fooController.Get();
//Here we are casting the expected type
var values = (OkNegotiatedContentResult<string>)result;
Assert.AreEqual("Foo", values.Content);
}
By the way, i noticed you're using the async keyword in your controller action but i don't see the await keyword.
Using the async keyword without an await will give you a warning and result in a synchronous operation.
Also, you dont have to cast your response as an IHttpActionResult, you could do something like i showed in my example, wrap your content inside an Ok(your content here) and you're good to go.

Categories