Pass exception object to API parameter in .NET Core - c#

I am working in Exception Logging, I have created API for that, API taking exception as parameter and few more thing.
[HttpPost]
[Route("/Log")]
public IEnumerable<string> Post([FromBody] WP2Exceptions wp2Exceptions)
{
ExceptionsModel exceptionsModel = new ExceptionsModel();
exceptionsModel = _exceptions.GetExceptionsByType(wp2Exceptions.exception.GetType().ToString());
ExceptionsLogModel exceptionLogModel = new ExceptionsLogModel();
exceptionLogModel.ExceptionID = exceptionsModel.ExceptionID;
exceptionLogModel.ModuleName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
exceptionLogModel.ExceptionMessage = wp2Exceptions.exception.Message;
exceptionLogModel.ExceptionType = wp2Exceptions.exception.GetType().ToString();
exceptionLogModel.ExceptionSource = wp2Exceptions.exception.Source.ToString();
exceptionLogModel.ExceptionUrl = wp2Exceptions.exception.StackTrace;
_exceptionsLog.AddExceptionsLog(exceptionLogModel);
return new string[] { exceptionsModel.ExceptionType, exceptionsModel.Message };
}
public class WP2Exceptions
{
public string moduleName { get; set; }
public Exception exception { get; set; }
}
While i am passing exception in parameter i am getting "Bad Request" error
Test Code
public async void callAPI()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:50558/");
try
{
string s = null;
string sp = s.ToString();
}
catch (Exception ex)
{
var mydata = "{'exception':'" + JsonConvert.SerializeObject(ex) + "','moduleName':'WEBAPI'}";
var response = await client.PostAsync("Log", new StringContent(mydata, Encoding.UTF8, "application/json"));
if (response != null)
{
Console.WriteLine("Log ID - " + response.ToString());
}
}
}
Please correct me where i am doing wrong or is it possible can we pass exception object as a WEB API parameter?

I resolve the problem,
In remove below code.
var mydata = "{'exception':'" + JsonConvert.SerializeObject(ex) + "','moduleName':'WEBAPI'}";
Created new class and pass the data .
public class paramObject
{
public string modulename { get; set; }
public Exception exception { get; set; }
}
Inside callAPI method i implement following code.
pramObject po = new pramObject()
{
modulename="Webapi",
exception=ex,
};
var response = await client.PostAsync("Log", new StringContent(JsonConvert.SerializeObject(po), Encoding.UTF8, "application/json"));

Related

Updating Item in Sharepoint List with HttpClient through API fails with 403 FORBIDDEN (create and delete is working)

I try to do some CRUD operations on a sharepoint list, unfortunately I cannot update an item in the list. Since I can create and also delete items from the list, I think everything is fine with authentication and rights, but maybe I am not aware of some specific for the update process.
I have extracted the code from my libs to thrill it down to the most relevant lines, in an async method I first read the list and get the item to update
async Task Main()
{
var BaseUrl = "https://my_site/";
var credentials = new NetworkCredential("user", "pass", "domain");
string RequestDigest = null;
HttpClientHandler handler = new HttpClientHandler { Credentials = credentials };
var SpClient = new HttpClient(handler)
{
BaseAddress = new Uri(BaseUrl)
};
SpClient.DefaultRequestHeaders.Accept.Clear();
SpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var url = BaseUrl + $"_api/lists/getbytitle('Test')/items";
var response = await SpClient.GetAsync(url);
var data = await response.Content.ReadAsStringAsync();
if (response.StatusCode != HttpStatusCode.OK) throw new Exception(response.StatusCode.ToString() + " - " + response.RequestMessage.RequestUri);
SharepointListItems listEntries = JsonSerializer.Deserialize<SharepointListItems>(data);
var existing = listEntries.ListItems.FirstOrDefault(p => p.Title == "Eins");
This works fine, existing now contains the item from the list.
Now I tried to update this item:
// This will not work: StatusCode: 403, ReasonPhrase: 'FORBIDDEN', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
existing.Title = "Changed";
string jsonString = JsonSerializer.Serialize<SharepointListItem>(existing);
So I tried to set up the sting for the item "by Hand" for testing purpose:
// This will also not work : StatusCode: 403, ReasonPhrase: 'FORBIDDEN', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
// Prepare body string for testing
string jsonString = "{\"__metadata\": { \"type\": \"SP.Data.TestListItem\" }, \"Title\": \"Changed\"}";
Finally this is the code, that writes the item back to the list:
// write item back to list
if (RequestDigest == null || DateTime.Now > Convert.ToDateTime(RequestDigest.Split(',')[1]).AddSeconds(1800))
{
url = BaseUrl + "_api/contextinfo";
response = await SpClient.PostAsync(url, null);
data = response.Content.ReadAsStringAsync().Result;
var result = JsonSerializer.Deserialize<SharepointContext>(data);
RequestDigest = result.FormDigestValue;
SpClient.DefaultRequestHeaders.Remove("X-RequestDigest");
SpClient.DefaultRequestHeaders.Add("X-RequestDigest", RequestDigest);
SpClient.DefaultRequestHeaders.Add("X-HTTP-Method", "MERGE");
SpClient.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
}
if (existing.odataetag != null)
{
SpClient.DefaultRequestHeaders.Remove("If-Match");
SpClient.DefaultRequestHeaders.Add("If-Match", $"*");
}
var content = new StringContent(jsonString);
content.Headers.Clear();
content.Headers.Add("Content-Type", "application/json");
content.Headers.Add("X-RequestDigest", RequestDigest);
content.Headers.Add("X-HTTP-Method", "MERGE");
url = BaseUrl + $#"_api/lists/getbytitle('Test')/items({existing.Id})";
response = await SpClient.PostAsync(url, content);
Console.WriteLine(response.StatusCode);
response.Dump();
}
This sample I have extracted from my code and written in LinqPad. Here are the classes required for the full sample to run:
public class SharepointListItems
{
[JsonPropertyName("odata.metadata")]
public string odatametadata { get; set; }
[JsonPropertyName("value")]
public List<SharepointListItem> ListItems { get; set; }
}
public class SharepointListItem
{
public SharepointListItem() { }
[JsonPropertyName("odata.type")]
public string odatatype { get; set; }
[JsonPropertyName("odata.id")]
public string odataid { get; set; }
[JsonPropertyName("odata.etag")]
public string odataetag { get; set; }
[JsonPropertyName("odata.editLink")]
public string odataeditLink { get; set; }
public string Title { get; set; }
public int Id { get; set; }
}
public class SharepointContext
{
public string odatametadata { get; set; }
public int FormDigestTimeoutSeconds { get; set; }
public string FormDigestValue { get; set; }
public string LibraryVersion { get; set; }
public string SiteFullUrl { get; set; }
public string[] SupportedSchemaVersions { get; set; }
public string WebFullUrl { get; set; }
}
May anyone give any tips what I am doing wrong here?
As stated above the code runs fine on creating a new item. The only difference is that the body in this case only contains the item as Json without metadata and the etag header is not set.
Thank's for any hint.

How to get the return message from Web Api Problem?

I have this method in my Web Api.
[HttpPost("add", Name = "AddCampaign")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<CampaignDTOResponse>> AddCampaign([FromBody] CampaignDTORequest newCampaign)
{
try
{
var campaign = _mapper.Map<Campaign>(newCampaign);
campaign = await _campaignService.AddCampaignAsync(campaign);
var campaignDtoResponse = _mapper.Map<CampaignDTOResponse>(campaign);
return CreatedAtAction(nameof(GetCampaignById), new { id = campaignDtoResponse.Id }, campaignDtoResponse);
}
catch (Exception ex)
{
_logger.LogError(0, ex, ex.Message);
return Problem(ex.Message);
}
}
and here is my test in Xunit.
[Fact]
public async Task AddCampaign_ReturnBadRequestWhenStartDateIsGreaterThanEndDate()
{
var client = _factory.CreateClient();
string title = string.Format("Test Add Campaign {0}", Guid.NewGuid());
var campaignAddDto = new CampaignDTORequest
{
Title = title, StartDate = new DateTime(2021, 6, 7), EndDate = new DateTime(2021, 6, 6)
};
var encodedContent = new StringContent(JsonConvert.SerializeObject(campaignAddDto), Encoding.UTF8, "application/json");
var response = await client.PostAsync("/api/Campaign/add", encodedContent);
Assert.False(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
}
When the test pass in invalid date range, I got the validation error message in the Web Api.
How do I get this validation error message in Xunit so that I can assert it?
Problem is inside ControllerBase class.
As per the documentation on MSDN about Problem it returns an instance of ObjectResult.
The ObjectResult is a result, it may contain further data in the form of JSON. By default it contains the data from class ProblemDetails. Also the default status code will be 500.
So in your code following assertions sould pass
Assert.False(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
To get the error message from the response.. you need to convert the response body to a class object which has the same structure as ProblemDetails class.
public class ApiProblem
{
public string Type { get; set; }
public string Title { get; set; }
public int Status { get; set; }
public string Detail { get; set; }
public string TraceId { get; set; }
}
Then you need to deserialize the response body to an object of this class.
var responseContent = await response.Content.ReadAsStringAsync();
var apiProblem = JsonConvert.DeserializeObject<ApiProblem>(responseContent);
And then use Detail property of the object to assert the error message.
Assert.Equal("The campaign start date can not be greater than end date", apiProblem.Detail);
I hope this will help you solve your issue.

Read / Load JSON response from PHP Web API to WPF ComboBox

Below is my JSON response from PHP Web API. I need this "tradeType" to be loaded in WPF ComboBox after checking "success"is true/false, If false display Error message shown in "message"
{
"success":"true",
"message":"Trade Type List",
"tradeType":[
{"id":1, "name":"Coaching Class"},
{"id":2,"name":"Food Supply"},
{"id":3,"name":"Marriage Bureau"}
]
}
I am new to WPF and Web API, what i have tried is
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://offline.localhost.in/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/utilities/trade_types").Result;
if (response.IsSuccessStatusCode)
{
var jsonString = response.Content.ReadAsStringAsync();
Root myDeserializedClass = JsonConvert.DeserializeObject<List<TradeType>>(jsonString);
cmbTrade.ItemsSource = users;
}
else
{
MessageBox.Show("Error Code" + response.StatusCode + " : Message - " + response.ReasonPhrase);
}
var jsonString = response.Content.ReadAsStringAsync();
You are missing an await here so the call is fired but not awaited. Also have Task in var instead the string.
var jsonString = await response.Content.ReadAsStringAsync();
or use the non-async version.
public class TradeType
{
public int id { get; set; }
public string name { get; set; }
}
public class Root
{
public string success { get; set; }
public string message { get; set; }
public List<TradeType> tradeType { get; set; }
}
private void GetData()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://offline.localhost.in/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/utilities/trade_types").Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(result);
myDeserializedClass.tradeType.Insert(0, new TradeType { id = 0, name = "-Select-" });
cmbTrade.ItemsSource = myDeserializedClass.tradeType;
cmbTrade.DisplayMemberPath = "name";
cmbTrade.SelectedValuePath = "id";
cmbTrade.SelectedIndex = 0;
}
else
{
MessageBox.Show("Error Code" + response.StatusCode + " : Message - " + response.ReasonPhrase);
}
}

How to use streams, to generate csv file, using CsvHelper in .NET Core 3.1?

I am developing an api, which has to return csv file on some endpoint. Here's my controller responsible for csv generation:
[ApiController]
[Route("api/[controller]")]
[Authorize]
public sealed class ReportController : BaseController
{
public ReportController(ICommandBus commandBus,
IQueryBus queryBus)
: base(commandBus, queryBus)
{
}
[HttpGet]
public async Task<IActionResult> GetReportAsync([FromQuery] GenerateReportRequest request)
{
try
{
var report = await QueryBus
.SendAsync<GenerateReportQuery, Report>(new GenerateReportQuery
{
Filters = request.Filters,
ResponseFileFormat = request.ResponseFileFormat,
WithPodOnly = request.WithPodOnly
});
return File(report.Content,
report.Type,
report.Name);
}
catch (Exception e)
{
// ToDo: Handle exception in proper way
return StatusCode(StatusCodes.Status500InternalServerError,
e.Message);
}
}
}
When the request comes to my api, certain handler is invoked, and the csv generation starts in CsvGenerationStrategy class, which is attached below:
public class CsvGenerationStrategy : IReportGenerationStrategy
{
public async Task<Report> GenerateReportAsync(ICollection<ShipmentEntity> shipmentEntities)
{
var shipment = shipmentEntities
.Select(s => (Shipment) s)
.ToList();
await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);
csvWriter.Configuration.Delimiter = ";";
await csvWriter.WriteRecordsAsync(shipment);
var content = memoryStream.ToArray();
var report = new Report
{
Content = content,
Type = ReportConstants.CsvFileType,
Name = ReportConstants.CsvReportFileName
};
return report;
}
private class Shipment
{
[Name(ReportConstants.IssueColumnName)]
public string Issue { get; set; }
[Name(ReportConstants.MaterialReleaseReceiptColumnName)]
public string MaterialReleaseReceipt { get; set; }
[Name(ReportConstants.FreightBillIssueColumnName)]
public string FreightBillIssue { get; set; }
[Name(ReportConstants.InvoiceNumberColumnName)]
public string InvoiceNumber { get; set; }
[Name(ReportConstants.TaxCodeColumnName)]
public string TaxCode { get; set; }
[Name(ReportConstants.ContractorIdColumnName)]
public string ContractorId { get; set; }
[Name(ReportConstants.AddressIdColumnName)]
public string AddressId { get; set; }
[Name(ReportConstants.ContractorNameColumnName)]
public string ContractorName { get; set; }
[Name(ReportConstants.ShipmentCountryColumnName)]
public string ShipmentCountry { get; set; }
public static explicit operator Shipment(ShipmentEntity entity) =>
entity != null
? new Shipment
{
Issue = entity.Issue,
MaterialReleaseReceipt = entity.MaterialReleaseReceipt,
FreightBillIssue = entity.FreightBillIssue,
InvoiceNumber = entity.InvoiceNumber,
TaxCode = entity.TaxCode,
ContractorId = entity.ContractorId,
AddressId = entity.AddressId,
ContractorName = entity.ContractorName,
ShipmentCountry = entity.ShipmentCountry
}
: null;
}
}
The code looks properly, but the behavior of the class is quite strange. In most cases, the generation runs properly, but few times i have noticed a situation, when the MemoryStream object contains no data, even if shipment collection is correct. I believe, such a behavior does not depend on data passed as a parameter. Probably i've made something wrong with the streams. How to use them properly? How to generate csv file correctly using CsvHelper library?
I've found a solution. StreamWriter has to be flushed, after writing records, so now the function looks like:
public async Task<Report> GenerateReportAsync(ICollection<ShipmentEntity> shipmentEntities)
{
var shipment = shipmentEntities
.Select(s => (Shipment) s)
.ToList();
await using var memoryStream = new MemoryStream();
await using var streamWriter = new StreamWriter(memoryStream);
await using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);
csvWriter.Configuration.Delimiter = ";";
await csvWriter.WriteRecordsAsync(shipment);
await streamWriter.FlushAsync();
var report = new Report
{
Content = memoryStream.ToArray(),
Type = ReportConstants.CsvFileType,
Name = ReportConstants.CsvReportFileName
};
return report;
}
And it works properly :)

Autofill with REST API in windows 8.1 phone app

I am implementing a city search so I want a Autofill with the functionality where when I select a city I want the ID to be sent back to the API. to populate some other fields.
private async void AutoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
string text = sender.Text;
if (text.Length >= 3)
{
GetCities(text);
sender.ItemsSource = await Task<string[]>.Run(() => { return this.GetSuggestions(text); });
}
else
{
sender.ItemsSource = new string[] { "No suggestions..." };
}
}
}
My Get response class
private async void GetCities(string city)
{
try
{
string baseAddress = Url.url + "searchCities?q="+city+"&access_token=" + tcm;
HttpClient httpClient = new HttpClient();
string co = "";
var content = await httpClient.GetAsync(new Uri(baseAddress));
if (!content.IsSuccessStatusCode)
{
TokenGenerator tc = new TokenGenerator();
tc.GetToken();
tcm = TokenManager.accessT.access_tocken;
HttpClient client = new HttpClient();
content = await client.GetAsync(new Uri(baseAddress));
}
co = await content.Content.ReadAsStringAsync();
AutofillHelper result = JsonConvert.DeserializeObject<AutofillHelper>(co);
foreach (var item in result.data)
{
suggestions = new string [] {item.city} ;
}
}
catch (Exception ex)
{
dispatcherTimer.Stop();
throw new Exception(ex.ToString());
}
}
private string[] GetSuggestions(string text)
{
string[] result = null;
result = suggestions.Where(x => x.StartsWith(text)).ToArray();
return result;
}
My Get Set
class Autofill
{
public string city_id { get; set; }
public string city { get; set; }
}
class AutofillHelper
{
public List<Autofill> data { get; set; }
}
I want it to display the response from the API for the person to select it. A Run time error is thrown. Can someone please guide me what has gone wrong.
Any kind of help is appreciated...

Categories

Resources