So, I'm porting an app over to Windows Store. At the start of the app, I have some code, that asks a question. I DO NOT WANT THE REST OF MY CODE TO FIRE UNTIL I GET A RESPONSE.
I have this:
string message = "Yadda Yadda Yadda";
MessageDialog msgBox = new MessageDialog(message, "Debug Trial");
msgBox.Commands.Add(new UICommand("OK",
(command) => { curSettings.IsTrial = true; }));
msgBox.Commands.Add(new UICommand("Cancel",
(command) => { curSettings.IsTrial = false; }));
await msgBox.ShowAsync();
//... more code that needs the IsTrial value set BEFORE it can run...
When I run the app, the code after the msgBox.ShowAsync() runs, without the correct value being set. It's only after the method finishes that the user sees the Dialog box.
I would like this to work more like a prompt, where the program WAITS for the user to click BEFORE continuing the method. How do I do that?
MessageDialog does not have a non-asynchronous method for "Show." If you want to wait for the response from the dialog before proceeding, you can simply use the await keyword.
Here also is a quickstart guide for asynchronous programming in Windows Store Apps.
I see that your code sample already uses "await". You must also mark the calling function as "async" in order for it to work properly.
Example:
private async void Button1_Click(object sender, RoutedEventArgs e)
{
MessageDialog md = new MessageDialog("This is a MessageDialog", "Title");
bool? result = null;
md.Commands.Add(
new UICommand("OK", new UICommandInvokedHandler((cmd) => result = true)));
md.Commands.Add(
new UICommand("Cancel", new UICommandInvokedHandler((cmd) => result = false)));
await md.ShowAsync();
if (result == true)
{
// do something
}
}
Related
I've used Hellang Middleware for exception handling as the global exception handling mechanism in my MVC application.
I've added the following code in the ConfigureServices method in Startup.cs:
services.AddProblemDetails(opts =>
{
// Control when an exception is included
opts.IncludeExceptionDetails = (ctx, ex) =>
{
// Fetch services from HttpContext.RequestServices
var env = ctx.RequestServices.GetRequiredService<IHostEnvironment>();
return env.IsDevelopment() || env.IsStaging();
};
opts.ShouldLogUnhandledException = (ctx, e, d) =>
{
return (d.Status.HasValue && d.Status.Value >= 500);
};
});
Also I've added UseProblemDetails() in Configure method.
However I came to know that if am using UseProblemDetails(), then UseExceptionHandler() won't work!
Hence I'am not able to figure out a method for navigating user to a common error view page.
Is there any way to redirect users to an error page while sticking on to Hellang Middleware for exception handling and logging ?
See the answer here:
https://stackoverflow.com/a/40153711/90287
You have to distinguish between the type of request, if it's an API request or a UI request to determine if a problem+details JSON should be returned or if a web page should be returned, respectively.
This is what I do near the top of the Configure method of Startup.cs:
app.UseWhen(context => context.IsApiRequest(), branch =>
{
branch.UseProblemDetails();
});
app.UseWhen(context => !context.IsApiRequest(), branch =>
{
branch.UseExceptionHandler("/Home/Error");
});
You can define your own custom HttpContext extension method:
public static class HttpContextExtensions
{
public static bool IsApiRequest(this HttpContext context)
{
return context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)
|| (context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"); // AJAX request
}
}
I had a similar problem. I solved it like the following. In this example logging a custom business fault exception:
services.AddProblemDetails(setup =>
{
setup.Map<FaultException<BusinessFault>>((context, exception) =>
{
// resolve logger
var logger = context.RequestServices.GetRequiredService<ILogger<ProblemDetails>>();
// log exception to Seq
logger.LogError(exception, "{#Exception} occurred.", exception);
// return the problem details map
return new ProblemDetails
{
Title = exception.Message,
Detail = exception.Detail.FaultMessage,
Status = exception.Detail.FaultType.ToHttpStatus(),
Type = exception.Detail.FaultType.ToString(),
Instance = exception.Detail.FaultReference
};
});
});
This is not exactly the answer to your question, but I had a similar issue in a Web API application regarding using ExceptionHandler middleware and Hellang ProblemDetails Middleware and I also came to realize I could't use them both because both change the response in their own way and affect one another.
Based on the documentation here you can use one of the configuration options of the ProblemDetails package to excute code before changing response and there you can log all the information you need.
services.AddProblemDetails(options =>
{
options.IncludeExceptionDetails = (context, ex) =>
{
var environment = context.RequestServices.GetRequiredService<IWebHostEnvironment>();
return environment.IsDevelopment();
};
options.Map<IdentityException>(exception => new ProblemDetails()
{
Title = exception.Title,
Detail = exception.Detail,
Status = StatusCodes.Status500InternalServerError,
Type = exception.Type,
Instance = exception.ToString()
});
options.OnBeforeWriteDetails = (ctx, pr) =>
{
//here you can do the logging
logger.LogError("Exception Occurred!!!!");
logger.LogError(pr.Detail);
logger.LogError(pr.Instance);
};
});
Here, I use a custom exception with extra fields that are needed for problem details object in response, and I use the Instance field to hold the exception and log it.
I'm trying to call an injected HttpClient during operations within a Razor Component. When I do so during OnInitialized, the return is as expected. When I do so on an event like an input change, the client call doesn't respond.
I'm using a mix of MVC Controllers/Views with Razor Components in .Net Core 3.1.
Startup.cs
services.AddControllersWithViews()...
services.AddRazorPages()...
services.AddHttpClient<IJiraService, JiraService>("jira", c =>
{
c.BaseAddress = new Uri(Configuration.GetSection("ApplicationSettings:Jira:Url").Value);
var auth =
$"{Configuration.GetSection("ApplicationSettings:Jira:UserName").Value}:{Configuration.GetSection("ApplicationSettings:Jira:Password").Value}";
var authHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth));
c.DefaultRequestHeaders.AddAuthorization("Basic", authHeaderValue);
c.Timeout = TimeSpan.FromSeconds(20);
c.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue
{
NoCache = true
};
});
ChildComponent.razor
#inject IJiraService JiraService
#code {
public int SelectedReleaseId
{
get => ReleaseModel.SelectedReleaseId;
set
{
ReleaseModel.SelectedReleaseId = value;
ReleaseChanged().Wait();
}
}
}
#functions
{
private async Task ReleaseChanged()
{
if (ReleaseModel.SelectedReleaseId > 0)
{
var url = "...";
await JiraService.GetResponseAsync(url);
}
}
JiraService.cs
public async Task<string> GetResponseAsync(string url)
{
var resp = await httpClient.GetAsync(url); // <--- this is the call that never returns when invoked from an input control event
var respContentString = await resp.Content.ReadAsStringAsync();
if (resp.StatusCode != HttpStatusCode.OK)
{
throw new HttpOperationException(
$"Invalid response from Jira service: {resp.StatusCode}: {respContentString}");
}
return respContentString;
}
There's actually a bit of service classing in between, but this is the jist.
I've abstracted the call up to a parent component and implemented EventCallbacks all with the same result. The underlying call in the JiraService gets hit and i see a breakpoint stop on the await httpClient.GetAsync(url); but then execution just goes into the ether. There's not even an exception thrown or timeout.
It all seems so obvious now. The problem was a deadlock. This old post helped me realize that my property based #bind attribute was synchronously calling into an async/await graph. I refactored this into an #onchange function that enabled appropriate async/await behavior through the call stack and viola, await httpClient.GetAsync() behaved just like it should.
A little annoyed at the #bind behavior that takes the onchange event functionality in addition to the property value.
I'm trying to get some custom columns values (longitude,latitude) from ASPNetUsers Table from the DB , When I send a Get request throw browser I get a 200 ok with the requested json .. but when I try to use GetStringAsync to deserialize the response in my xamarin app I don't get any response .
In AccountController class
// POST api/Account/GetUserPostion
[Route("GetUserPostion")]
public LocationDataToPostAsync GetUserPostion()
{
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new ApplicationUserManager(store);
LocationDataToPostAsync locationData = new LocationDataToPostAsync();
var model = manager.FindById(User.Identity.GetUserId());
locationData.UserId = User.Identity.GetUserId();
if (model.Longitude != null) locationData.Longitude = (double) model.Longitude;
if (model.Latitude != null) locationData.Latitude = (double) model.Latitude;
return locationData;
}
In ApiService class in xamarin forms app
public async Task<LocationDataToPostAsync> GetUserLocationAsync(string accessToken)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await client.GetStringAsync("http://10.0.2.2:45455/api/Account/GetUserPostion");
var location = JsonConvert.DeserializeObject<LocationDataToPostAsync>(json);
return location;
}
It is unclear from your code if the Task is awaited or you are calling .Result or .GetAwaiter().GetResult() on the Task. However, as we found out in the comments adding .ConfigureAwait(false) fixed your issue.
This indicates that the code cannot return to the context it came from, so adding .ConfigureAwait(false) the code doesn't return to the context.
In your case the context is probably the UI thread and when it tries to return the UI thread is blocked.
The most likely scenario why the UI Thread is block is because you called your Task in a wrong manner. If you call it with .Result on the UI thread you are synchronously blocking the UI thread, hence anything that tries to return to the UI thread, will deadlock, since you are blocking that.
The easy fix here is to just add .ConfigureAwait(false) in your code. The better solution would be not to block the UI thread by awaiting the Task.
My app need to access location service, for that I am asking user to whether to enable location, if user says yes, then I am opening location settings. Upto this is working. But how to detect/handle when user coming from location page to my application page.
Here is my code
private async Task<Geoposition> getCurrentLocation()
{
Geoposition position = null;
Geolocator locator = new Geolocator() { DesiredAccuracyInMeters = 10 };
var flag = true;
try
{
position = await locator.GetGeopositionAsync(TimeSpan.FromHours(1), TimeSpan.FromSeconds(30));
flag = false;
}
catch (Exception uae)
{
}
if (flag)
{
await ShowLocationPage();
}
}
getCurrentLocation method called when page is loaded. If it didnt get user location then ShowLocationPage method get called.
private static async Task ShowLocationPage()
{
ContentDialog cd = new ContentDialog(){
Content = "Application want to access your location. Would you like to turn on Location Services?",
PrimaryButtonText = "Yes",
SecondaryButtonText = "No"
};
var result = await cd.ShowAsync(); if (result == ContentDialogResult.Primary)
{
var x = await Windows.System.Launcher.LaunchUriAsync(new Uri("ms-settings-location:"));
}
}
My problem is how to detect that user return from location page, so I can check for geo-information again.
Best way to get this going is to check if your app get's focus again ( or is resumed ).
With the new wp RT this has changed a bit against wp SL.
A bit to long to explain here in StackO answer, but a very compleet explanation is up here http://www.interact-sw.co.uk/iangblog/2013/07/24/return-xaml-store-app
Some disscussion about it was up on twitter few days back: https://twitter.com/rschu/status/498836593269305344
I am trying to get a reference to a response stream before its complete in windows phone 8.
In other .Net platforms you can do
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(myUri);
WebResponse subscribeWebResponse = null;
Stream subscribeStream = null;
subscribeWebResponse = httpRequest.GetResponse();
subscribeStream = subscribeWebResponse.GetResponseStream();
For the purpose of creating Portable class libraries I've used the HttpClientLibrary from nuget.
This Adds ref to extensions assembly Microsoft.Net.Http
this allows me to return the async request at the time the headers have been read instead of waiting for the content transfer to be complete with
var clientResponse = await httpClient.SendAsync(requestmessage, HttpCompletionOption.ResponseHeadersRead);
The problem I'm having is that in windows phone 8 it doesn't work correctly, and still awaits the completion of the content stream to return.
Additionally
await httpWebRequest.BeginGetResponse(callback, request)
has the same behavior as these async methods are actually waiting for the completion of the web's response to continue execution.
So, is there any way to achieve the returning the response/stream at the point that i have received the response headers without Microsoft.Http.Net package?
Even if it has to be a Windows Phone 8 Platform Specific Solution?
Possibly an extension of HttpWebRequest?
From what I can tell, ResponseHeadersRead works on the WP8 emulator as it does on the desktop.
I installed the Win8 SDK. Created a windows phone app. I added this code to the MainPage ctor. This demonstrates a very rudimentary long polling example.
var client = new HttpClient();
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://oak:1001/longpolling")
};
client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, new CancellationToken())
.ContinueWith((t) =>
{
var response = t.Result;
response.Content.ReadAsStreamAsync()
.ContinueWith(s =>
{
var st = s.Result;
while (true)
{
var message= ReadNextMessage(st);
}
});
});
}
private static string ReadNextMessage(Stream stream)
{
int chr = 0;
string output = "";
while (chr != 10)
{
chr = stream.ReadByte();
output += Convert.ToChar(chr);
}
return output;
}
On my host dev machine I have a web api with a controller that looks like this...
public class LongPollingController : ApiController
{
public HttpResponseMessage Get()
{
Thread.Sleep(2000);
var content = new PushStreamContent( (s,c,t) =>
{
int i = 0;
while (true)
{
try
{
var message = String.Format("The current count is {0} " + Environment.NewLine, i++);
var buffer = Encoding.UTF8.GetBytes(message);
s.Write(buffer, 0, buffer.Length);
}
catch (IOException exception)
{
s.Close();
return;
}
Thread.Sleep(1000);
}
});
return new HttpResponseMessage(HttpStatusCode.OK)
{
RequestMessage = Request,
Content = content
};
}
}
So here's the deal. I would say that what you want to do is not possible, due to platform limitations... But SignalR has a WP client and is able to manage it. So it seems to me you have two options:
1) Dig into the SignalR source code to see how they do it (I'm on my phone right now so I can't provide a link).
UPDATE: Here is the link. They do some pretty neat tricks, like setting the Timeout to -1 for long-running clients. I think you should definitely use the techniques here.
OR
2) You can move whatever you're doing over to SignalR, which would gain the benefit of having a robust infrastructure and being cross-platform compatible.
HTH