Xamarin CrossMediaManager cannot queue from PlayfromResources - xamarin.forms

I am trying to Queue all MP3 files in Embedded resources using
CrossMediaManager PlayFromAssembly(string, assembly);
Play from assembly only supports string name of single file theres no way of adding multiple files from embedded resources.
Appreciate any help from yours.

First, you can use a list to add resources by url like this:
public IList<string> Mp3UrlList => new[]{
"https: a,
"https: b,
"https: c,
};
await CrossMediaManager.Current.Play(Mp3UrlList);
Second, this method can play the resourses in the folder, here is the code:
await CrossMediaManager.Android.PlayFromResource(Resource.Raw.somefile.ToString());

Related

Deleting a folder from Firebase Cloud Storage in Flutter

I have a Flutter mobile app in which I am trying to delete a folder (and its contents) from Firebase Cloud Storage. My method is as follows:
deleteFromFirebaseStorage() async {
return await FirebaseStorage.instance.ref().child('Parent folder/Child folder').delete();
}
I expect Child folder and its contents to be deleted, but this exception is thrown:
Unhandled Exception: PlatformException(Error -13010, FIRStorageErrorDomain, Object Parent folder/Child folder does not exist.)
However I can clearly see that folder exists in Cloud Storage. How do I delete this folder?
MD. Saffan Alvy was right, but to completely delete all and not just one file
do this.
if you didn't know.
await await FirebaseStorage.instance.ref("users/${FirebaseAuth.instance.currentUser!.uid}/media").listAll().then((value) {
value.items.forEach((element) {
FirebaseStorage.instance.ref(element.fullPath).delete();
);
});
Cloud Storage doesn't actually have any folders. There are just paths that look like folders, to help you think about how your structure your data. Each object can just have a common prefix that describes its "virtual location" in the bucket.
There's no operations exposed by the Firebase SDKs that make it easy to delete all objects in one of these common prefixes. Your only real option is to list all files in a common prefix, iterate the results, and delete each object individually.
Unfortunately, the list files API has not made it to flutter yet, as discussed here. So you are kind of out of luck as far as an easy solution is concerned. See also: FirebaseStorage: How to Delete Directory
Your primary viable options are:
Keep track of each object in a database, then query the database to get the list of objects to delete.
Delete the objects on a backend using one of the server SDKs. For example: Delete folder in Google Cloud Storage using nodejs gcloud api
I built a script that deletes recursively all files inside a folder and all subfolders, here is:
import 'package:firebase_storage/firebase_storage.dart';
class FirebaseStorageApi {
static Future<void> deleteFolder({
required String path
}) async {
List<String> paths = [];
paths = await _deleteFolder(path, paths);
for (String path in paths) {
await FirebaseStorage.instance.ref().child(path).delete();
}
}
static Future<List<String>> _deleteFolder(String folder, List<String> paths) async {
ListResult list = await FirebaseStorage.instance.ref().child(folder).listAll();
List<Reference> items = list.items;
List<Reference> prefixes = list.prefixes;
for (Reference item in items) {
paths.add(item.fullPath);
}
for (Reference subfolder in prefixes) {
paths = await _deleteFolder(subfolder.fullPath, paths);
}
return paths;
}
}
Usage:
await FirebaseStorageApi.deleteFolder(path: "YOUR/FOLDER/PATH");
Currently, I'm working on a project that contains a single file inside every folder so I did this and it worked for me.
await FirebaseStorage.instance.ref("path/" + to + "/" + folder)
.listAll().then((value) {
FirebaseStorage.instance.ref(value.items.first.fullPath).delete();
});
This code deletes the file and folder as well. Since, there's no folder here, deleting the file deletes the folder or reference. You can use foreach loop or map to delete everything from the folder if you have multiple files.

NLog: Write to two different targets based on logger name and grouping Quartz logs

I have an ASP.NET 4.7 web project where there is a Quartz.NET scheduler implemented.
I've read that Quartz.NET is using Common.Logging abstraction, but I don't know what it really means...
In order to avoid my default application log to be spammed from Quartz messages, I have configured programmatically the NLog settings, in the following way:
var config = new NLog.Config.LoggingConfiguration();
var logfile = new NLog.Targets.FileTarget("logfile")
{
FileName = "${basedir}/Logs/${logger}_${shortdate}.log",
Layout = "${longdate}|${level:uppercase=true}|${aspnet-request-ip}|${aspnet-request-url}|${callsite}|${message}|${exception:format=tostring}"
};
var logfileQ = new NLog.Targets.FileTarget("logfile")
{
FileName = "${basedir}/Logs/Quartz_${shortdate}.log",
Layout = "${longdate}|${level:uppercase=true}||${message}"
};
config.AddTarget(logfile);
config.AddTarget(logfileQ);
config.AddRule(LogLevel.Error, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
// Apply config
NLog.LogManager.Configuration = config;
NLog.LogManager.ReconfigExistingLoggers();
Then I add my application logs with the following code:
public class MyApiController : ApiController
{
private static NLog.Logger logger = NLog.LogManager.GetLogger("Application");
[HttpPost]
[Authorize]
public IHttpActionResult Post(DataModel.MyModel m)
{
logger.Warn("Unable to add point {0}: localization missing", m.Name);
}
}
So NLog creates an "application_yyyy-MM-dd.log" file correctly and also a "Quartz_yyyy-MM-dd.log" file with only the error and fatal message levels.
The problem is that it creates also the following three files for Quartz containing all levels:
Quartz.Core.JobRunShell_2020-04-28.log
Quartz.Core.QuartzSchedulerThread_2020-04-28.log
Quartz.Simpl.SimpleJobFactory_2020-04-28.log
It seems like final=true of the first rule is ignored.
Which is the right way to configure it? Should I have to disable something in Quartz?
I finally figured it out.
The added rules must be seen as filters, what doesn't match a filter go to the next rule.
The last one is like "take everything that has not been matching before..."
The main issue in mine rules is the first one that match only the levels Error and Fatal, but all the other levels of Quartz message step into the next rule that writes the log file.
Therefore the rules should be like this:
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
In this way, all the messages, of any levels, coming from Quartz will be written in the quartz_ log file.
To avoid a trace or info level of Quartz to be recorded I should add a third rule to grab also them and placed before the "grab all" rule:
config.AddRule(LogLevel.Warn, LogLevel.Fatal, logfileQ, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Info, noLogging, "Quartz*", true);
config.AddRule(LogLevel.Trace, LogLevel.Fatal, logfile, "*");
Where noLogging is a target that doesn't write anywhere or only to console

Xamarin.Forms - How to access /data/user/0/com.companyname.notes/files/.local/share/

I was following a small tutorial of Microsoft.
Which basically saves your text input onto the internal memory of your device.
String _filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Notes.txt");
Results in: /data/user/0/com.companyname.notes/files/.local/share/Notes.txt for me.
Now, while everything works, I would like to see this Notes.txt file in the folder.
I have searched far and wide, but can't seem to find a way to locate this file on my device.
I can go to Android/data/com.companyname.notes/files but then I only see a ._override_ folder with the app project files in it, but without the Notes.txt
Any ideas?
Thanks
From your path:/data/user/0/com.companyname.notes/files/.local/share/Notes.txt, we can know that you want to access internal storage, but Internal storage refers to the non-volatile memory that Android allocates to the operating system, APKs, and for individual apps. This space is not accessible except by the operating system or apps. So you can not find this text file from internal storage.
If you want to see file, you can save this file in external storage
/storage/emulated/0/Android/data/com.companyname.app/files
More detailed info about internal storage, see:
https://learn.microsoft.com/en-us/xamarin/android/platform/files/
Update
If you want to save text file, you should declare one of the two permissions for external storage in the AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then the primary location for private external files is found by calling the method Android.Content.Context.GetExternalFilesDir(string type). This method will return a Java.IO.File object that represents the private external storage directory for the app. Passing null to this method will return the path to the user's storage directory for the application. As an example, for an application with the package name com.companyname.app, the "root" directory of the private external files would be:
/storage/emulated/0/Android/data/com.companyname.app/files/
In the Forms, you need to create new interface:
public interface IFileSystem
{
string GetExternalStorage();
}
Implement this interface in Android:
[assembly: Dependency(typeof(FileSystemImplementation))]
namespace FileApp.Droid
{
public class FileSystemImplementation : IFileSystem
{
public string GetExternalStorage()
{
Context context = Android.App.Application.Context;
var filePath = context.GetExternalFilesDir("");
return filePath.Path;
}
}
}
Now you can create text file and save text in this file:
private async void Btn1_Clicked(object sender, EventArgs e)
{
var folderPath = DependencyService.Get<IFileSystem>().GetExternalStorage();
var file = Path.Combine(folderPath, "count.txt");
using (var writer = File.CreateText(file))
{
await writer.WriteLineAsync("123456789000000000000000000000000000000000000");
}
}
I have made a sample:
https://github.com/CherryBu/FileApp
The exact path to the private external storage directory can vary from device to device and between versions of Android.
Open your File Manager App
Go to Android/data
Find the .com folder, in your case, com.companyname.notes
Follow the path until you find the file

XUnit Net Core Web API Integration Test: "The ConnectionString property has not been initialized."

Just trying to build an Integration Test project for a NET Core Web API.
So I've followed a few examples, including this one (https://dotnetcorecentral.com/blog/asp-net-core-web-api-integration-testing-with-xunit/) and naturally, I run into issues. When I run the simple GET test I get an exception:
"System.InvalidOperationException : The ConnectionString property has not been initialized."
Any help would be appreciated.
For server = new TestServer(new WebHostBuilder().UseStartup<Startup>());, you need to manually configure the appsettings.json path like
var server = new TestServer(WebHost.CreateDefaultBuilder()
.UseContentRoot(#"D:\Edward\SourceCode\AspNetCore\Tests\IntegrationTestMVC")
// This is the path for project which needs to be test
.UseStartup<Startup>()
);
For a convenience way, I would suggest you try Basic tests with the default WebApplicationFactory.
The WebApplicationFactory constructor infers the app content root path by searching for a WebApplicationFactoryContentRootAttribute on the assembly containing the integration tests with a key equal to the TEntryPoint assembly System.Reflection.Assembly.FullName. In case an attribute with the correct key isn't found, WebApplicationFactory falls back to searching for a solution file (*.sln) and appends the TEntryPoint assembly name to the solution directory. The app root directory (the content root path) is used to discover views and content files.
Reference:How the test infrastructure infers the app content root path
I had to override CreateHostBuilder in my derived WebApplicationFactory in order to add the configuration for the connection string (since it was read from user secrets).
public class CustomApplicationFactory : WebApplicationFactory<Sedab.MemberAuth.Startup>
{
protected override IHostBuilder CreateHostBuilder()
{
var initialData = new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("ConnectionStrings:DefaultConnection", "test")
};
return base.CreateHostBuilder().ConfigureHostConfiguration(config => config.AddInMemoryCollection(initialData));
}
}

Is it a bad idea to use synchronous filesystem methods in a Dart web server?

I'm playing around with HttpServer; and was adding support for serving static files (I'm aware of Shelf; I'm doing this as a learning exercise). I have a list of handlers that are given the opportunity to handle the request in sequence (stopping at the first that handles it):
const handlers = const [
handleStaticRequest
];
handleRequest(HttpRequest request) {
// Run through all handlers; and if none handle the request, 404
if (!handlers.any((h) => h(request))) {
request.response.statusCode = HttpStatus.NOT_FOUND;
request.response.headers.contentType = new ContentType("text", "html");
request.response.write('<h1>404 File Not Found</h1>');
request.response.close();
}
}
However, as I implemented the static file handler, I realised that I couldn't return true/false directly (which is required by the handleRequest code above, to signal if the request is handled) unless I use file.existsSync().
In something like ASP.NET, I wouldn't think twice about a blocking call in a request because it's threaded; however in Dart, it seems like it would be a bottleneck if every request is blocking every other request for the duration of IO hits like this.
So, I decided to have a look in Shelf, to see how that handled this; but disappointingly, that appears to do the same (in fact, it does several synchronous filesystem hits).
Am I overestimating the impact of this; or is this a bad idea for a Dart web service? I'm not writing Facebook; but I'd still like to learn to write things in the most efficient way.
If this is considered bad; is there a built-in way of doing "execute these futures sequentially until the first one returns a match for this condition"? I can see Future.forEach but that doesn't have the ability to bail. I guess "Future.any" is probably what it'd be called if it existed (but that doesn't)?
Using Shelf is the right approach here.
But there is still a trade-off between sync and async within the static handler package.
Blocking on I/O obviously limits concurrency, but there is a non-zero cost to injecting Future into a code path.
I will dig in a bit to get a better answer here.
After doing some investigation, it does not seem that adding async I/O in the shelf_static improves performance except for the bit that's already async: reading file contents.
return new Response.ok(file.openRead(), headers: headers);
The actual reading of file contents is done by passing a Stream to the response. This ensures that the bulk of the slow I/O happens in a non-blocking way. This is key.
In the mean time, you may want to look at Future.forEach for an easy way to invoke an arbitrary number of async methods.
There are a lot of good questions in your post (perhaps we should split them out into individual SO questions?).
To answer the post title's question, the best practice for servers is to use the async methods.
For command-line utilities and simple scripts, the sync methods are perfectly fine.
I think it becomes a problem if you do file access that is blocking for a long time (reading/writing/searching big files locally or over the network).
I can't imagine file.existsSync() doing much damage. If you are already in async code it's easy to stay async but if you have to go async just for the sake of not using file.existsSync() I would consider this premature optimization.
A little offtopick, but it solved my problem, I was trying to solve by reading discussion on this question. I was not able to achieve async operation in handler with io.serve, so I used dart:io for active pages and shelf.handleReguest for static files:
import 'dart:io';
import 'dart:async' show runZoned;
import 'package:path/path.dart' show join, dirname;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_static/shelf_static.dart';
import 'dart:async';
import 'package:sqljocky/sqljocky.dart';
void main(){
HttpServer
.bind(InternetAddress.ANY_IP_V4, 9999)
.then((server) {
server.listen((HttpRequest request) {
String path = request.requestedUri.path;
if(path == "/db"){
var pool = new ConnectionPool(host: 'localhost', port: 3306, user: 'root', db: 'db', max: 5);
var result = pool.query("select * from myTable");
result.then((Results data) {
data.first.then((Row row) {
request.response.write(row.toString());
request.response.close();
});
});
}else{
String pathToBuild = join(dirname(Platform.script.toFilePath()), '..', 'build/web');
var handler = createStaticHandler(pathToBuild, defaultDocument: 'index.html');
io.handleRequest(request, handler);
}
});
});
}
Many months later I've found how to create that Stream... (still offtopick .. a little)
shelf.Response _echoRequest(shelf.Request request) {
StreamController controller = new StreamController();
Stream<List<int>> out = controller.stream;
new Future.delayed(const Duration(seconds:1)).then((_){
controller.add(const Utf8Codec().encode("hello"));
controller.close();
});
return new shelf.Response.ok(out);
}

Resources