I'm trying to make some downloads using cookie authentication doing:
var downloader = new BackgroundDownloader();
downloader.SetRequestHeader("Cookie", "JSESSIONID=" + App.LoginGateway.JSESSIONID);
downloader.SetRequestHeader("Cookie", "JSESSIONID=" + App.LoginGateway.JSESSIONID);
Until here everything works perfectly, the problem begins when I try to restore my downloads and my JSESSIONID is expired
IReadOnlyList<DownloadOperation> downloads = null;
downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
I tried to find where could I set the request Header again but I was not capable. If I create a new BackgroundDownloader where could I set it for my download Operation?? Some Help is very appreciated
As of Windows 8.1, BackgroundTransfer does not support updating the headers associated with a DownloadOperation/UploadOperation after the operation has been created, even if the operation is Paused/Resumed. You'll need to abort the old download and create a new download with an updated JSESSIONID header.
When your application is launched, it should be using BackgroundDownloader.GetCurrentDownloadsAsync() to query for all the DownloadOperations that might have been occurring in the background while your app was suspended/terminated. Your application should then call AttachAsync on each DownloadOperation in order to attach progress and completion handlers. In this case, you should implement logic in your completion handler that can identify this particular error case and create a new download (with the new JSESSIONID) for the same content.
As an aside, if you go searching for other folks that need to post-process failed downloads like this, you may run across some people who are performing these checks in Background Tasks that they register to run on a periodic timer. While this may sound like a good idea (since it means you could retry your download without waiting for the next time the user brings your application to the foreground), keep in mind that BackgroundTransfer may hang if you attempt to call AttachAsync in a Background Task for an operation which was started in your foreground application code.
Related
When creating a .NET Core Web app C# and debugging you can opt to Launch the browser when Running the app. The console launches and then the url launches in your preferred browser. Once you close the browser tab opened by the debug session, the app process it stop and is no longer running on the machine.
When I published the app, the page does not launch automatically so I am starting a new Process to do so. I've added an event handler to the process before starting it but the since the app didn't launch the process it doesn't receive any notification when the tab has been closed.
What is the proper way to go about launching your .NET Core web app and/or handle communicating between the two?
I even tried adding a Close button but JS won't allow me to close the window as I haven't opened it.
I'm creating my Process as follows:
var p = Process.Start("cmd", "/C start http://localhost:5000");
I've tried
p.WaitForExit();
p.EventHandler += newHandler;
and I also tried using ProcessStartInfo but the only thing that is working right now is if I set a Timer and then kill the process when the timer is activated but this doesn't seem too clean.
Any advice is appreciated!
I wanted to follow-up with the process I feel is the most graceful way that I am happy with.
A few pieces of info that may be helpful in creating your own process. It was a goal of mine to use .net core to self host a client side web app which communicates with a server hosted web api.
I am using Razor views and .net core 3.1
I am using Startup and utilizing applicationLifeTime to handle OnStartup where I start the process as I described in my original post.
At this point the web app opens and if the user decides to close the browser the process doesn't know and continues to run in the background.
In order to prevent it from continuing to run and allow the user to initiate it closing, I made a few the following additions.
First, I added a timer that uses a configurable length of time via appsettings. When starting the process that opens the browser I call and set the timer that will perform an "AutoShutdown" if the process is still running after the configurable length of time that I defaulted to 1hr. I am using Enviroment.Exit(0) in the event that handles closing the running process.
My View is using a Model that contains a property who's value will be set from the page via a hidden field.
I added a Close button to the View that is displayed to the user at startup. When the user clicks close, I use jquery to set a hidden field in the view and then I use jquery to submit the form.
When the Model is received, the value set by the client's request to close is true and you can handle the close without display errors if you use a Timer and Start it almost immediately after redirecting the View to a view with a message to the client. Whether they leave it open or close it, the process will have closed. Example of how I did it below.
Finally, in Main.cs I put a check in to check if there is an existing process running and close it before starting a new one. I added this because the client may not always close the browser and/or they may attempt to start it before the "AutoShutdown" timer has kicked in.
This is more "hacky" then I would like but I couldn't find anything else that didn't throw and show Bad Request when trying to use Envirnoment.Exit(0) when the client is still has the view open and I was unsuccessful at being able to allow console input so that I could send close to the console.
This is how I am handling the close request from the client in my Controller
if (ui.HandleCloseApp)
{
var app = Process.GetProcessesByName("NameOfYourWebApp");
if (app.Length >= 1)
{
foreach (var p in app)
{
if (p.ProcessName == "NameOfYourWebApp")
{
p.Close();
p.Dispose();
}
}
}
var t = new System.Timers.Timer(10);
t.Elapsed += OnClose;
t.Start();
return View("Close");
}
I hope this helps someone else in creating their own "graceful" process that shouldn't be :)
I'm still open if anyone has input to share. Thx!
I got that downloader code running on Windows 10 IoT Core which tries to download a file to the applications local folder if it does not exist yet. If it does, it should return the path to that file.
Spoiler: The code snippet itself is working, see below.
private async Task<string> GetAsync(string url)
{
url = WebUtility.UrlDecode(url);
string fileName = Path.GetFileName(url);
var folder = ApplicationData.Current.LocalFolder;
var destinationFile = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
if (new FileInfo(destinationFile.Path).Length > 0)
return destinationFile.Path;
var downloader = new BackgroundDownloader();
var download = downloader.CreateDownload(new Uri(url), destinationFile);
await download.StartAsync();
return destinationFile.Path;
}
Now, when the file does not exist, the code is running until line await download.StartAsync(). From there, it never returns.
In the folder, an empty file with the given name is existent but only 0kb in size - that one's created implicitly while calling CreateFileAsync() before (and that's why I check for .Length to check the file existence).
Now comes the thing:
That code is never returning, but if I kill the application (after enough time), the file gets written to disk, so the download apparantly succeeded but it did not "flush" to the file system. That does not happen if I do not kill the app, so refreshing the Windows Explorer view or looking for the file properties does not show any change in size.
I'm getting crazy on this, could somebody give me a hint? All the tips and hints from articles like those here did not work on the Pi:
BackgroundDownloader.GetCurrentDownloadsAsync returns completed downloads
Check progress of download operation which started in background task
MSDN: Background transfers: Post processing
Setup
Raspberry Pi 3
Windows 10 IoT Core 10.0.15063.0
Wired Ethernet connection
App capabilities (Package.appxmanifest)
Internet (Client & Server)
Internet (Client)
Private Networks (Client & Server)
Removable Storage
This hanging can be caused by Async and WPF context locking. Try to use Task.Wait() instead of await. WPF UI locks awaits easily.
I got my await SpiDevice.FromIdAsync(devs[0].Id, set) locked, and when I changed to devTask.Wait(), lock disappeared and device found from devTask.Result.
I want to create some functions in ASP.NET Web API, which should be executed daily at specific time and do specific task like update statuses/Records/Generating Emails, SMS.
Should i create a TaskService in Code
using System;
using Microsoft.Win32.TaskScheduler;
class Program
{
static void Main(string[] args)
{
// Get the service on the local machine
using (TaskService ts = new TaskService())
{
// Create a new task definition and assign properties
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Does something";
// Create a trigger that will fire the task at this time every other day
td.Triggers.Add(new DailyTrigger { DaysInterval = 2 });
// Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(new ExecAction("notepad.exe", "c:\\test.log", null));
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition(#"Test", td);
// Remove the task we just created
ts.RootFolder.DeleteTask("Test");
}
}
}
or should i create a .bat file and create a new task in Task Scheduler.
As you have mentioned in the question, you need to do the specific tasks like update statuses/Records/Generating Emails, SMS etc.
So database access comes into the scenario and on the other hand, you will have to send emails and SMS's which may require third party libraries or other configuration setting access.
Thus, to do all this it will be better to go with code implementation via which you can maintain your changes and requirements well enough.
About the ".bat file and windows scheduler", you need to have great skills using the limited batch commands available to fulfill your requirement.
So, my suggestion is code, .exe and windows scheduler task.
Also, this should be a separate application, don't mix it up with Web API code. You can always create a new project in the web API solution with web API project and reuse whatever code is possible.
You should do this outside your web code. This is because your webapp should have no access to the task system or web service. By default IIS 7.5+ runs app's in their own limited user account (https://www.iis.net/learn/manage/configuring-security/application-pool-identities).
If you want to have a reliable tasks scheduling wherein you can apply time interval depend on your choice, I recommend [quartz]: https://www.quartz-scheduler.net/. Quartz allow to add/edit/delete/etc a scheduled task easily, manageable and no CPU overhead.
Moreover Quartz is an open source job scheduling system that can be used from smallest apps to large scale enterprise systems.
I recommend you to try Hangfire. It's free and you can use it for free in commercial app. Ducumentation you can find here.
I have a simple Windows Universal Platform Application that I wrote primarily to teach myself about UWP apps. It works fine, except for what appears to be a somewhat random "The RPC server is unavailable" error generated on the OpenReadAsync method on the StorageFile object.
The application simply builds a list of files to be displayed, then iterates through and displays each one on a timer. Most of the time it works fine. I can let it run for hours no problem. But every once in a while, I receive the RPC error. It seems to happen when I leave the machine for a long time so it logs me out, then I log back in and switch to my slideshow application. It doesn't happen every time, and if I try to reproduce, I can never get it to fail. It seems to be mainly when I leave the machine for a long time - like overnight.
Here is the code running when the error occurs. It happens on the OpenReadAsync method call.
StorageFile file = this._files.ElementAt(this._index++);
await this._dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var bitmap = new BitmapImage();
var stream = await file.OpenReadAsync();
await bitmap.SetSourceAsync(stream);
this.Image = bitmap;
});
If I try to open the file using the Windows Photo viewer, even while sitting at the error, it opens fine. But even re-trying the failing line of code will not allow my app to open the file. All I can do is shut down and restart the application.
Has anyone run across anything like this? Any hints on where I should look?
Thanks.
Edit: Oh, one more thing - the files are all on a local drive. No external servers or network involved.
I am developing an WP8 app that uses a webbrowser control that shows statefull server content. On WP8 you can switch between apps manually. E.g. if you want to copy&paste some information from one app into a browser input field. If you switch that way, the current app instance stays alive. That means the web session and the current page of the browser control will stay available.
Now I want another app to send some data directly into the app with the browser control - without restarting it...
From what I know, there are three ways to handle inter app communication:
register a file type that will open the app by launching that file from local storage
register an app protocol and use Launcher.LaunchUriAsync() to submit parameters in a query string
use a shared storage file
Detailed information can be found here.
I think the last approach is not usefull, because after you have started the second app, there is now way to activate the calling app or is there any usefull way to reactivate the webbrowser app?
I tried the second approach, but I am running in an issue, because it starts a new instance by design. That means InitializePhoneApplication is called. There is the entry point for the custom UriMapper that reads the incoming parameters. So the old app instance is killed and all session data, cookies and input fields are gone. With WP webbrowser control you are not able to store the cookie and page state, so a fast app resume is not possible also.
private void InitializePhoneApplication()
{
if (this.phoneApplicationInitialized)
{
return;
}
RootFrame = new TransitionFrame();
RootFrame.Navigated += this.CompleteInitializePhoneApplication;
RootFrame.UriMapper = new AssociationUriMapper();
//...
this.phoneApplicationInitialized = true;
}
Is there any other way or a possibility to use the shown approaches to send data between apps without restarting them using LanchUri()?
That means, to send some data back to a running instance without reinitializing the whole app, so that the page state and session state are still available on the target app.
Best regards
Holger
FastAppResume is the solution. I haven't used it and thought it also reinitiates the app. But it doesnt. This example shows how to reuse the existing instance.
Regards
Holger