Windows Store App UI - not responsive - windows-8

I'm trying to get my head around designing a UI that remains responsive while a long running task is being executed.
To that end, I created a simple app in VS2012 and added the following class to it:
using System.Threading.Tasks;
namespace TaskTest
{
class Class1
{
public async Task<int> Async()
{
//simulate a long running process
for (long x = 0; x < long.MaxValue; x++) { }
return 1;
}
}
}
I then modified the main page's LoadState() method thusly:
protected override async void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
await DoLongRunningProcess();
}
private async Task DoLongRunningProcess()
{
var id = 0;
id = await new Class1().Async();
await new MessageDialog(id + "").ShowAsync();
}
I want the page to remain responsive while that process executes. However, when I run this code, the page takes a long time to load. What am I doing wrong?
TIA

async isn't magic; it just gives you the capability to write asynchronous code. In particular, async does not execute code on a background thread. You can use Task.Run to do this.
You may find my async/await intro or the MSDN documentation helpful.

That was helpful. I made the following changes and I got the result I was looking for:
class Class1
{
public int Launch()
{
//throw new Exception("Class1 exception");
for (var i = 0; i < int.MaxValue / 2; i++) ;
return 1;
}
}
...
protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
var task = DoLongRunningProcess();
await task;
await new MessageDialog(task.Result + "").ShowAsync();
}
private Task<int> DoLongRunningProcess()
{
return Task.Run<int>(() => new Class1().Launch());
}
The page continues to load and after a short pause the message dialog is displayed. Now however, I need to know how to catch exceptions. If I uncomment the //throw new Exception ... line in method Launch(), it is reported as an unhandled exception. I want to catch this exception in the main UI thread (i.e., in the body of method LoadState) but I can't seem to manage it.

Related

Accessing HttpContext.Session from static method

I am getting following error when accessing HttpContext.Session from static method placed in separate task:
Session has not been configured for this application or request.
I used this article to implement access to HttpContext outside the controller
From controller I invoke this static method that used to retrieve image data:
public static void CreateDummyGallery(Gallery gallery)
{
Logger.LogDebug(LogModule.Dummy, $"Starting gallery creation.");
Task.Factory.StartNew(() =>
{
try
{
List<DummyPicture> pictures;
using (var context = new MyzeumContext())
{
int top = 10;
pictures = context.DummyPictures.FromSql($"SELECT * FROM dummypictures ORDER BY RAND() LIMIT {top}").ToList();
}
Logger.LogDebug(LogModule.Dummy, $"Starting retrieving images.");
Parallel.ForEach(pictures, picture => {
using (WebClient client = new WebClient())
{
}
});
Logger.LogDebug(LogModule.Dummy, $"Done retrieving images.");
}
catch(Exception e)
{
Logger.LogError(LogModule.Server, e.Message, e);
}
});
}
The problem occurs in Logger.LogDebug() because this is where I access HttpContext:
public void LogDebug(LogModule module, string message, Exception stackTrace = null)
{
Log record = new Log();
record.Module = module;
record.ThreadId = Environment.CurrentManagedThreadId;
record.SessionId = HttpContextHelper.Current?.Session?.Id;
record.Message = message;
record.Logged = DateTime.UtcNow;
if(stackTrace != null)
{
record.Message += $" :{stackTrace.StackTrace}";
}
queue.Enqueue(record);
}
The problem 99% occurs in the first call inside task:
Logger.LogDebug(LogModule.Dummy, $"Starting retrieving images.");
BUT, right after application starts this whole task block works fine and does not throw any exception. Problem starts after following requests.

Where to call async GetDataFromServer in Xamarin.Forms?

Where would be the best place to call GetDataFromServer method?
My gut feeling and reason say it belongs in the repository, but I've no clue where to call it. I've tried to call it in the constructor, but that didn't work out too well. It had issues with it being an async method.
public class SQLiteRepository : ISQLiteRepository
{
private HttpClient _httpClient = new HttpClient();
private readonly SQLiteAsyncConnection _efContext;
public SQLiteRepository()
{
_efContext = DependencyService.Get<ISQLiteDb>().GetAsyncConnection();
_efContext.CreateTableAsync<EfPartner>();
}
public async Task<IEnumerable<EfPartner>> GetAllPartnersAsync()
{
try
{
var partners = await _efContext.Table<EfPartner>().ToListAsync();
return partners;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task GetDataFromServerAsync()
{
try
{
var partners = await GetPartnersFromServerAsync();
var companies = await GetCompaniesFromServerAsync();
await _efContext.InsertAllAsync(partners);
}
catch (Exception ex)
{
throw ex;
}
}
private async Task<IEnumerable<EfPartner>> GetPartnersFromServerAsync()
{
try
{
var jsonObject = await _httpClient.GetStringAsync(Constants.PartnersUrl);
var dotNetObject = JsonConvert.DeserializeObject<List<EfPartner>>(jsonObject);
return new List<EfPartner>(dotNetObject);
}
catch (Exception ex)
{
throw ex;
}
}
private async Task<IEnumerable<EfCompany>> GetCompaniesFromServerAsync()
{
try
{
var jsonObject = await _httpClient.GetStringAsync(Constants.CompaniesUrl);
var dotNetObject = JsonConvert.DeserializeObject<List<EfCompany>>(jsonObject);
return new List<EfCompany>(dotNetObject);
}
catch (Exception ex)
{
throw ex;
}
}
}
I called the GetDataFromServerAsync from PartnersListPage.xaml.cs -> which feels wrong.
I'd appreciate any help.
Thank you.
============================ UPDATE ============================
The app I'm working on creates the pages in a MasterDetailPage like so:
private void MenuListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
return;
var menuItem = e.SelectedItem as EfMenuItem;
if (menuItem == null)
return;
var page = (Page)Activator.CreateInstance(menuItem.TargetPage);
page.Title = menuItem.Title;
Detail = new NavigationPage(page);
IsPresented = false;
MdpMasterPage.MenuListView.SelectedItem = null;
}
And here is the PartnersListPage.xaml.cs, from where is GetDataFromServer called at the moment:
public partial class PartnersListPage : ContentPage
{
private readonly SQLiteRepository _repo;
public PartnersListPage()
{
InitializeComponent();
_repo = new SQLiteRepository();
}
protected override async void OnAppearing()
{
await _repo.GetDataFromServerAsync();
var partners = await _repo.GetAllPartnersAsync();
InitializeGrid(partners);
base.OnAppearing();
}
This is an important topic related to MVVM, what you are doing is "correct" but it may have issues later on once your application grow bigger, let's imaging this scenario:
The user is a desperate one and he/she wants to Navigate on your app real fast, he/she open this specific page 5 or 10 times, what will happen then?
Your OnAppearing() method will be called every time the user lands on this page and a new thread will be created for instance your application will start to behave poorly on the performance part. (Specially on Android).
So my suggestion will be to use an MVVM framework to handle those cases based on the pattern, here is a small tutorial using Prism:
https://xamgirl.com/prism-in-xamarin-forms-step-by-step-part-1/
And in regards of your question, your UI ListView specifically your ItemSource (If you are using a ListView) property should be binded to your GetAllPartnersAsync() return type.
If that is not the case and based on the context I suppose InitializeGrid(partners); is creating cells for a Grid in your XAML class so I suppose you can debug step by step if the UI is being created correctly. A Grid does not have an ItemSource property
If you want to have a Grid with an ItemSource property I suggest you sue this ones:
https://github.com/Manne990/XamTest
https://github.com/daniel-luberda/DLToolkit.Forms.Controls/tree/master/FlowListView

Task.WaitAll(...) blocks on MVC 4 application

In a MVC 4 application I have a task that copies a file to a destination folder. Because I have multiple files, I create a task for every file, and I want to wait untill they all finish. The problem is my code blocks at Task.WaitAll(copyingTasks.ToArray()) as if the tasks never end, so it never passes that line of code. Below you have the sample code:
private void CopyFilesFromWorkingCopyForProject(string projectName)
{
var copyingTasks = new List<Task>
{
CopyAllFromDirectoryToDirectory(FilesUtils.AndroidConfigsPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyAllFromDirectoryToDirectory(FilesUtils.AndroidValuesPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyFileToDirectory(FilesUtils.AndroidManifestPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyAllFromDirectoryToDirectory(FilesUtils.IosConfigsPath(), FilesUtils.IosPathForProject(projectName))
};
Task.WaitAll(copyingTasks.ToArray());
}
private async Task CopyAllFromDirectoryToDirectory(string sourceDirectory, string destinationDirectory)
{
foreach (string filename in Directory.EnumerateFiles(sourceDirectory))
{
await CopyFileToDirectory(filename, destinationDirectory);
}
}
private async Task CopyFileToDirectory(string filename, string destinationDirectory)
{
using (FileStream sourceStream = File.Open(filename, FileMode.Open))
{
using (FileStream destinationStream = File.Create(destinationDirectory + filename.Substring(filename.LastIndexOf('\\'))))
{
await sourceStream.CopyToAsync(destinationStream);
}
}
}
If I comment Task.WaitAll(copyingTasks.ToArray()); it doesn't block anymore, but I want to wait for all the files to be copied.
Combining await and synchronous wait leads to deadlocks, because async methods try to resume on the context that's currently blocked by your wait.
What you should do instead is to make CopyFilesFromWorkingCopyForProject() also async (and the method that calls that, and the method that calls that, …):
private async Task CopyFilesFromWorkingCopyForProject(string projectName)
{
var copyingTasks = new List<Task>
{
CopyAllFromDirectoryToDirectory(FilesUtils.AndroidConfigsPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyAllFromDirectoryToDirectory(FilesUtils.AndroidValuesPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyFileToDirectory(FilesUtils.AndroidManifestPath(), FilesUtils.AndroidPathForProject(projectName)),
CopyAllFromDirectoryToDirectory(FilesUtils.IosConfigsPath(), FilesUtils.IosPathForProject(projectName))
};
await Task.WhenAll(copyingTasks);
}
If you can't or don't want to do that, you need to make sure the async methods don't resume on the current context. To do that, you can use ConfigureAwait(false) for all your awaits, or you can call the async methods on a background thread using Task.Run().

Maximum threads issue

To begin with, I checked the discussions regarding this issue and couldn't find an answer to my problem and that's why I'm opening this question.
I've set up a web service using restlet 2.0.15.The implementation is only for the server. The connections to the server are made through a webpage, and therefore I didn't use ClientResource.
Most of the answers to the exhaustion of the thread pool problem suggested the inclusion of
#exhaust + #release
The process of web service can be described as a single function.Receive GET requests from the webpage, query the database, frame the results in XML and return the final representation. I used a Filter to override the beforeHandle and afterHandle.
The code for component creation code:
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8188);
component.getContext().getParameters().add("maxThreads", "512");
component.getContext().getParameters().add("minThreads", "100");
component.getContext().getParameters().add("lowThreads", "145");
component.getContext().getParameters().add("maxQueued", "100");
component.getContext().getParameters().add("maxTotalConnections", "100");
component.getContext().getParameters().add("maxIoIdleTimeMs", "100");
component.getDefaultHost().attach("/orcamento2013", new ServerApp());
component.start();
The parameters are the result of a discussion present in this forum and modification by my part in an attempt to maximize efficiency.
Coming to the Application, the code is as follows:
#Override
public synchronized Restlet createInboundRoot() {
// Create a router Restlet that routes each call to a
// new instance of HelloWorldResource.
Router router = new Router(getContext());
// Defines only one route
router.attach("/{taxes}", ServerImpl.class);
//router.attach("/acores/{taxes}", ServerImplAcores.class);
System.out.println(router.getRoutes().size());
OriginFilter originFilter = new OriginFilter(getContext());
originFilter.setNext(router);
return originFilter;
}
I used an example Filter found in a discussion here, too. The implementation is as follows:
public OriginFilter(Context context) {
super(context);
}
#Override
protected int beforeHandle(Request request, Response response) {
if (Method.OPTIONS.equals(request.getMethod())) {
Form requestHeaders = (Form) request.getAttributes().get("org.restlet.http.headers");
String origin = requestHeaders.getFirstValue("Origin", true);
Form responseHeaders = (Form) response.getAttributes().get("org.restlet.http.headers");
if (responseHeaders == null) {
responseHeaders = new Form();
response.getAttributes().put("org.restlet.http.headers", responseHeaders);
responseHeaders.add("Access-Control-Allow-Origin", origin);
responseHeaders.add("Access-Control-Allow-Methods", "GET,POST,DELETE");
responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
responseHeaders.add("Access-Control-Allow-Credentials", "true");
response.setEntity(new EmptyRepresentation());
return SKIP;
}
}
return super.beforeHandle(request, response);
}
#Override
protected void afterHandle(Request request, Response response) {
if (!Method.OPTIONS.equals(request.getMethod())) {
Form requestHeaders = (Form) request.getAttributes().get("org.restlet.http.headers");
String origin = requestHeaders.getFirstValue("Origin", true);
Form responseHeaders = (Form) response.getAttributes().get("org.restlet.http.headers");
if (responseHeaders == null) {
responseHeaders = new Form();
response.getAttributes().put("org.restlet.http.headers", responseHeaders);
responseHeaders.add("Access-Control-Allow-Origin", origin);
responseHeaders.add("Access-Control-Allow-Methods", "GET,POST,DELETE"); //
responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
responseHeaders.add("Access-Control-Allow-Credentials", "true");
}
}
super.afterHandle(request, response);
Representation requestRepresentation = request.getEntity();
if (requestRepresentation != null) {
try {
requestRepresentation.exhaust();
} catch (IOException e) {
// handle exception
}
requestRepresentation.release();
}
Representation responseRepresentation = response.getEntity();
if(responseRepresentation != null) {
try {
responseRepresentation.exhaust();
} catch (IOException ex) {
Logger.getLogger(OriginFilter.class.getName()).log(Level.SEVERE, null, ex);
} finally {
}
}
}
The responseRepresentation does not have a #release method because it crashes the processes giving the warning WARNING: A response with a 200 (Ok) status should have an entity (...)
The code of the ServerResource implementation is the following:
public class ServerImpl extends ServerResource {
String itemName;
#Override
protected void doInit() throws ResourceException {
this.itemName = (String) getRequest().getAttributes().get("taxes");
}
#Get("xml")
public Representation makeItWork() throws SAXException, IOException {
DomRepresentation representation = new DomRepresentation(MediaType.TEXT_XML);
DAL dal = new DAL();
String ip = getRequest().getCurrent().getClientInfo().getAddress();
System.out.println(itemName);
double tax = Double.parseDouble(itemName);
Document myXML = Auxiliar.getMyXML(tax, dal, ip);
myXML.normalizeDocument();
representation.setDocument(myXML);
return representation;
}
#Override
protected void doRelease() throws ResourceException {
super.doRelease();
}
}
I've tried the solutions provided in other threads but none of them seem to work. Firstly, it does not seem that the thread pool is augmented with the parameters set as the warnings state that the thread pool available is 10. As mentioned before, the increase of the maxThreads value only seems to postpone the result.
Example: INFO: Worker service tasks: 0 queued, 10 active, 17 completed, 27 scheduled.
There could be some error concerning the Restlet version, but I downloaded the stable version to verify this was not the issue.The Web Service is having around 5000 requests per day, which is not much.Note: the insertion of the #release method either in the ServerResource or OriginFilter returns error and the referred warning ("WARNING: A response with a 200 (Ok) status should have an entity (...)")
Please guide.
Thanks!
By reading this site the problem residing in the server-side that I described was resolved by upgrading the Restlet distribution to the 2.1 version.
You will need to alter some code. You should consult the respective migration guide.

How to handle error in Primefaces lazy load?

I have problem to let user know about exceptions occurred in PrimeFaces LazyDataModel#load method.
I am loading there data from database and when an exception is raised, I have no idea how to inform the user about it.
I tried to add FacesMessage to FacesContext, but message is not shown on the Growl component, even if Growl is set to autoUpdate="true".
Using PrimeFaces 3.3.
It doesn't work because load() method is invoked during Render Response phase (you can check this by printing FacesContext.getCurrentInstance().getCurrentPhaseId()), when all messages have already been processed.
The only workaround that worked for me is to load the data within the "page" event listener of the DataTable.
html:
<p:dataTable value="#{controller.model}" binding="#{controller.table}">
<p:ajax event="page" listener="#{controller.onPagination}" />
</p:dataTable>
Controller:
private List<DTO> listDTO;
private int rowCount;
private DataTable table;
private LazyDataModel<DTO> model = new LazyDataModel<DTO>() {
#Override
public List<DTO> load(int first, int pageSize, String sortField,
SortOrder sortOrder, Map<String, String> filters) {
setRowCount(rowCount);
return listDTO;
}
};
public void onPagination(PageEvent event) {
FacesContext ctx = FacesContext.getCurrentInstance();
Map<String, String> params = ctx.getExternalContext()
.getRequestParameterMap();
// You cannot use DataTable.getRows() and DataTable.getFirst() here,
// it seems that these fields are set during Render Response phase
// and not during Update Model phase as one can expect.
String clientId = table.getClientId();
int first = Integer.parseInt(params.get(clientId + "_first"));
int pageSize = Integer.parseInt(params.get(clientId + "_rows"));
try {
listDTO = DAO.query(first, pageSize);
rowCount = DAO.getRowCount();
} catch (SQLException e) {
ctx.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"SQL error",
"SQL error"));
}
}
Hope this helps.