I had place call between two Android devices which is running successfully. Now I want to implement Callback Rest API because of some server side decision before place call. As given in this image, ICE event fire and developer backend respond SVAML response.
Now I want to simply Hangup Call, for this I had done following code :
[System.Web.Http.HttpPost]
public SvamletModel MakeCall(CallbackEventModel model)
{
var sinch = SinchFactory.CreateCallbackResponseFactory(Locale.EnUs);
var reader = sinch.CreateEventReader();
var evt = reader.ReadModel(model);
var builder = sinch.CreateIceSvamletBuilder();
SvamletModel svaml = builder.Hangup().Model;
return svaml;
}
but call still placed. I had also write action class under SvamletModel but same response.
[System.Web.Http.HttpPost]
public SvamletModel MakeCall(CallbackEventModel model)
{
var sinch = SinchFactory.CreateCallbackResponseFactory(Locale.EnUs);
var reader = sinch.CreateEventReader();
var evt = reader.ReadModel(model);
var builder = sinch.CreateIceSvamletBuilder();
SvamletModel svaml = builder.Build().Model;
SvamletActionModel actionModel = new SvamletActionModel();
actionModel.Name = "Hangup";
svaml.Action = actionModel;
return svaml;
}
Note I had followed all steps given in Callback API and https://developers.sinch.com/docs/further-securing-your-sinch-calling-functionality-app-with-rest-api with no success.
Hi your code looks correct, can you capture and send here the HTTP response your backend is sending as response of the ICE POST?
Also add the callID for call.
Sinch Voice & Video Team
Converting return type from SvamletModel to string is working.
So I have changed
[System.Web.Http.HttpPost]
public SvamletModel MakeCall(CallbackEventModel model)
{
var sinch = SinchFactory.CreateCallbackResponseFactory(Locale.EnUs);
var reader = sinch.CreateEventReader();
var evt = reader.ReadModel(model);
var builder = sinch.CreateIceSvamletBuilder();
SvamletModel svaml = builder.Hangup().Model;
return svaml;
}
to
[System.Web.Http.HttpPost]
public string MakeCall(CallbackEventModel model)
{
var sinch = SinchFactory.CreateCallbackResponseFactory(Locale.EnUs);
var reader = sinch.CreateEventReader();
var evt = reader.ReadModel(model);
var builder = sinch.CreateIceSvamletBuilder();
SvamletModel svaml = builder.Hangup().Model;
string json = JsonConvert.SerializeObject(svaml, Formatting.Indented);
return json;
}
Related
I have the following code to call the bank api, and convert the response into the object.
public static async Task<ExchangeModel> LoadExchange(string currency, string date)
{
string url = "here is the bank's api url";
var streamTask = await _clientPolicy.LinearHttpRetry.ExecuteAsync(
() => _client.GetStreamAsync(url));
var deserialized = await JsonSerializer.DeserializeAsync<Root>(await streamTask);
var rate = deserialized.ExchangeModel.FirstOrDefault(r => r.Currency == currency);
return rate;
}
I wanted to add polly in order to retry api call if it failed. To do so, I created a policy client, but I don't know how to check if GetStreamAsync is succeed as it is a System.IO.Stream and it has no succeed status or something.
public AsyncRetryPolicy<System.IO.Stream> LinearHttpRetry { get; }
public ClientPolicy()
{
LinearHttpRetry = Policy.HandleResult<System.IO.Stream>(
res => !res.IsSuccessStatusCode).
WaitAndRetryAsync(5, retryAttempts => TimeSpan.FromSeconds(3));
}
In this example I kept it !res.IsSuccessStatusCode but there is no such parameter in my case.
Rather than calling directly the GetStreamAsync you can do the following "trick":
var response = await _client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
//TODO: Check response status code then
using var stream = await response.Content.ReadAsStreamAsync();
First you need to alter your policy definition like this:
public IAsyncPolicy<HttpResponseMessage> LinearHttpRetry { get; }
public ClientPolicy()
{
LinearHttpRetry = Policy
.HandleResult<HttpResponseMessage>(res => !res.IsSuccessStatusCode)
.WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(3));
}
Then you need to adjust the usage as well
public static async Task<ExchangeModel> LoadExchange(string currency, string date)
{
string url = "here is the bank's api url";
var response = await _clientPolicy.LinearHttpRetry.ExecuteAsync(
async () => await _client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead));
using var stream = await response.Content.ReadAsStreamAsync();
var deserialized = await JsonSerializer.DeserializeAsync<Root>(stream);
var rate = deserialized.ExchangeModel.FirstOrDefault(r => r.Currency == currency);
return rate;
}
My controller is returning File(res.File, "application/octet-stream", res.Filename); where res.File is an array of bytes.
I am running this controller using Kestrel, and this works fine for files are are under 128kb in size. Any larger, however, and the download of the file from the api simply stalls out at 128kb.
I'm clearly missing something. I can't find any reference to a limit for this kind of stuff.
I tried decorating the controller method with [DisableRequestSizeLimit], but oddly enough this made it start choking at 64kb.
I'm running dotnet 5.
Controller method
[HttpGet]
[Route("api/v1/reports/get-report")]
public FileResult DownloadReport(
string system,
string environment,
string company,
string quoteNumber,
string template,
string user)
{
var req = new GetQuoteReportRequest()
{
System = system,
Environment = environment,
Company = company,
QuoteNumber = quoteNumber,
Template = template,
User = user
};
return GenerateReportFile(req);
}
private FileResult GenerateReportFile(GetQuoteReportRequest req)
{
var res = _quoteReportService.GetQuoteReport(req);
return File(res.File, "application/octet-stream", res.Filename);
}
Service method
public GetQuoteReportResponse GetQuoteReport(GetQuoteReportRequest req)
{
var message = $"Generate {req.Template} report for quote {req.QuoteNumber}";
_logger.LogInformation($"START: {message}");
var res = new GetQuoteReportResponse();
var time = _timeService.Now;
var excelFilePath = GetExcelFilePath(time, req.QuoteNumber);
var quote = _dataLoader.GetQuote(req, IncludeInternalQuoteDetailLines);
using var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add(req.QuoteNumber);
Builder.BuildReport(worksheet,
quote,
req);
workbook.SaveAs(excelFilePath);
if (IsPdf)
{
var pdfFilePath = CreatePdf(excelFilePath);
res.Filename = Path.GetFileName(pdfFilePath);
res.File = File.ReadAllBytes(pdfFilePath);
}
else
{
res.File = File.ReadAllBytes(excelFilePath);
res.Filename = Path.GetFileName(excelFilePath);
}
_utilities.SendDbEntry(time,
Path.GetFileName(res.Filename),
quote.QuoteLines.Count,
req);
_logger.LogInformation($"END: {message}");
return res;
}
When i re-publish my project to my host, and try to display my view i get this error about 50% of the times depending on how lucky i am
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
my view gets called by
#if (Model.Items.Any())
{
var item = Model.Items.FirstOrDefault();
var table = item.GetValue("table");
// Render Action (controllerMethod, ControllerName, UmbracoModelData)
Html.RenderAction(table, "Monitor", new {data = item});
}
and this is my method in the controller that should return my view
public ActionResult Skader(LeBlenderValue data)
{
var jsonString = new WebClient { Encoding = System.Text.Encoding.UTF8 }.DownloadString("myStringHere");
var dbObj = JsonConvert.DeserializeObject<List<SkaderModel>>(jsonString);
var vm = new MonitorTableViewModel(){Skader = dbObj, gridData = data};
return PartialView("~/Views/Partials/Monitor/Skader.cshtml", vm);
}
I have a controller with the following actions:
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
[Route(
"/MyShop/OrderDetails/CancelOrder",
Name = UrlRouteDefinitions.MyShopOrderDetailsCancelOrder)]
[ValidateAntiForgeryToken]
public IActionResult CancelOrder(MyViewModel viewModel)
{
var isCancelSuccessful = _orderBusinessLogic.CancelOrderById(viewModel.Order.Id);
if (isCancelSuccessful)
{
//to show a success-message after the redirect
this.TempData["SuccessCancelOrder"] = true;
}
return RedirectToRoute(UrlRouteDefinitions.MyShopOrderDetailsIndex, new
{
orderId = viewModel.Order.Id
});
}
Then I also have the following piece of HTML in the View for the Controller mentioned above:
<div class="panel-body">
#if (TempData["SuccessCancelOrder"] != null)
{
//show the message
#TempData["SuccessCancelOrder"].ToString();
}
</div>
Now I'm writing an integration test (code-summary below) to check if the CancelOrder() method works as expected. There I'd like to access the value of the TempData dictionary to check its correctness.
[TestMethod]
public void MyTest()
{
try
{
//Arrange: create an Order with some Products
var orderId = CreateFakeOrder();
//Open the Order Details page for the arranged Order
var httpRequestMessage = base.PrepareRequest(
HttpMethod.Get,
"/MyShop/OrderDetails?orderId=" + orderId,
MediaTypeEnum.Html);
var httpResponse = base.Proxy.SendAsync(httpRequestMessage).Result;
var responseContent = httpResponse.Content.ReadAsStringAsync().Result;
var viewModel = base.GetModel<MyViewModel>(responseContent);
Assert.AreEqual(HttpStatusCode.OK, httpResponse.StatusCode);
//Try to execute a POST to cancel the Order
httpRequestMessage = base.PrepareRequest(
HttpMethod.Post,
"/MyShop/OrderDetails/CancelOrder",
MediaTypeEnum.Html,
httpResponse, content: viewModel);
httpResponse = base.Proxy.SendAsync(httpRequestMessage).Result;
var expectedRedirectLocation = $"{this.RelativeHomeUrl}/MyShop/OrderDetails?orderId=" + orderId;
var receivedRedirectLocation = WebUtility.UrlDecode(httpResponse.Headers.Location.ToString());
//we expect that the Order Details page will be reloaded
//with the ID of the already cancelled Order
Assert.AreEqual(HttpStatusCode.Redirect, httpResponse.StatusCode);
//-----------------------------------------------------------
//here I'm going to re-execute a GET-request
//on the Order Details page.
//
//Then I need to check the content of the message
//that's been written in the TempData
//-----------------------------------------------------------
}
finally
{
//delete the arranged data
}
}
In any case, I don't know how to access it from my integration test. Does anybody know how to do it and if there's a way at all?
Controller.TempData is public so you can easily access it and check if your key/value exists
[TestMethod]
public void TempData_Should_Contain_Message() {
// Arrange
var httpContext = new DefaultHttpContext();
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var controller = new TestController();
controller.TempData = tempData;
// Act
var result = controller.DoSomething();
//Assert
controller.TempData["Message"]
.Should().NotBeNull()
.And.BeEquivalentTo("Hello World");
}
I have a unique issue, I want to get the name of an application from it's AppID while I convert an XML file into objects. This is the code I'm using at present:
if (xdoc.Element("Application") != null)
{
var data = from query in xdoc.Descendants("AppID")
select new APP
{
AppID = query.Value,
AppName = GetName(query.Value).ToString(),
};
itemGridView.DataContext = data;
}
This is the code I'm using to convert the GUID into an app name using Microsoft's Store API. I can confirm that it does return the app name. I'm just unsure how I can get this to display.
private async Task<string> GetName(string guid)
{
try
{
string link = "https://services.apps.microsoft.com/browse/6.2.9200-1/615/en-NZ_en-NZ/c/NZ/cp/10005001/Apps/{0}";
string url = string.Format(link, guid);
var httpClient = new HttpClient();
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, url);
var response = await httpClient.SendAsync(httpRequestMessage);
var xmlString = await response.Content.ReadAsStringAsync();
XmlDocument NameXML = new XmlDocument();
NameXML = await XmlDocument.LoadFromUriAsync(new Uri(url));
string sAppName = NameXML.GetElementsByTagName("T")[0].ChildNodes[0].NodeValue.ToString();
return sAppName;
}
catch(Exception)
{
return guid;
}
}
I think my problem is with the async / await tasks. I've just been exposed to it now... how would I load up the App Name alongside the AppID when I parse the xml file?
The output that's being displayed when I run the app is "System.Threading.Tasks.Task[System.String]" (The objects load and the links and everything works fine, its just that the above is displayed instead of the app name).
I've been debugging using breakpoints, it appears that the GetName method only seems to be triggered later on, I'm not sure however.
Try to change this line :
AppName = GetName(query.Value).ToString(),
To this :
AppName = await GetName(query.Value),
GetName will return Task<string> instead of string when not awaited. And the method where above code resides required to be async because of using await inside that method :
private async void SomeMethod()
{
....
if (xdoc.Element("Application") != null)
{
var data = from query in xdoc.Descendants("AppID")
select new APP
{
AppID = query.Value,
AppName = await GetName(query.Value),
};
itemGridView.DataContext = data;
}
....
}
UPDATE :
As you already noticed, LINQ has very limited support for async/await currently. So to workaround this limitation, we can use normal for loop to avoid calling async function inside LINQ :
private async void SomeMethod()
{
....
if (xdoc.Element("Application") != null)
{
var query = from query in xdoc.Descendants("AppID")
select query.Value;
var data = new List<App>();
foreach (var q in query)
{
data.Add(new App{ AppId = q, AppName = await GetName(q) });
}
itemGridView.DataContext = data;
}
....
}