NSUrl Not Initializing properly - xamarin.forms

I've placed 25 mp3 files in the "Music folder" in my Xamarin.ios project.
I called the Play function and passed in the name of a mp3 file I want to play. I created a string object which contains the filePath.
Then I create a another string object called "withFileName" containing the path and song name passed into the function. The withFileName variable looks correct.
When I execute the instruction ...
songURL = new NSUrl(withFileName);
I get the following exception...
System.Exception: Could not initialize an instance of the type 'Foundation.NSUrl': the native 'initWithString:' method returned nil. It is possible to ignore this condition by setting MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure to false. at Foundation.NSO…
I'm lost, need some help.
code snippet:
public void Play(String song)
{
String dir = Directory.GetCurrentDirectory();
String filePath = Path.Combine(dir, "Music");
String withFileName = String.Format("{0}/{1}", filePath, song);
NSUrl songURL = null;
try
{
songURL = new NSUrl(withFileName);
}
catch (Exception e)
{
string msg = e.Message;
}
NSError err;
_audioPlayer = new AVAudioPlayer( songURL,"Song", out err );
_audioPlayer.Play();
}

It seems You can get the correct path of file embeded in the project. Then if you want to get the file's url you should use:
new NSUrl(filePath, false);
//or
NSUrl.FromFilename(filePath)

Related

the type or namespace name 'httpcontext 'does not exist in the namespace system.web(are you missing an assembly reference )

I got an error like this when trying to add google drive service to my project. Although there is "System.Web" in the "Library" section, it cannot be used actively. Could you help?
public static string DownloadGoogleFile(string fileId)
{
DriveService service = GetService();
string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/");
FilesResource.GetRequest request = service.Files.Get(fileId);
string FileName = request.Execute().Name;
string FilePath = System.IO.Path.Combine(FolderPath, FileName);
MemoryStream stream1 = new MemoryStream();
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the
// download is completed or failed.
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream1, FilePath);
break;
}
case DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream1);
return FilePath;
}
Trying to pass the current HttpContext to a static method gets tricky depending on the project framework. It's also not clear the type of project or framework you are using.
Here's a similar question that might help you clarify the difference between HttpContext when it pertains to .net and .net-core.
HttpContext in .net standard library

How to use "Azure storage blobs" for POST method in controller

I am creating an app where user can upload their text file and find out about its most used word.
I have tried to follow this doc to get used to the idea of using AZURE STORAGE BLOBS - https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-dotnet
But I am super newbie and having a hard time figuring it out how to adapt those blobs methods for my POST method.
This my sudo - what I think I need in my controller and what needs to happen when POST method is triggered.
a.No need for DELETE or PUT, not replacing the data nor deleting in this app
b.Maybe need a GET method, but as soon as POST method is triggered, it should pass the text context to the FE component
POST method
connect with azure storage account
if it is a first time of POST, create a container to store the text file
a. how can I connect with the existing container if the new container has already been made? I found this, but this is for the old CloudBlobContainer. Not the new SDK 12 version.
.GetContainerReference($"{containerName}");
upload the text file to the container
get the chosen file's text content and return
And here is my controller.
public class HomeController : Controller
{
private IConfiguration _configuration;
public HomeController(IConfiguration Configuration)
{
_configuration = Configuration;
}
public IActionResult Index()
{
return View();
}
[HttpPost("UploadText")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
if (files != null)
{
try
{
string connectionString = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING");
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
string containerName = "textdata" + Guid.NewGuid().ToString();
BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
//Q. How to write a if condition here so if the POST method has already triggered and container already created, just upload the data. Do not create a new container?
string fileName = //Q. how to get the chosen file name and replace with newly assignmed name?
string localFilePath = //Q. how to get the local file path so I can pass on to the FileStream?
BlobClient blobClient = containerClient.GetBlobClient(fileName);
using FileStream uploadFileStream = System.IO.File.OpenRead(localFilePath);
await blobClient.UploadAsync(uploadFileStream, true);
uploadFileStream.Close();
string data = System.IO.File.ReadAllText(localFilePath, Encoding.UTF8);
//Q. If I use fetch('Home').then... from FE component, will it receive this data? in which form will it receive? JSON?
return Content(data);
}
catch
{
//Q. how to use storageExeption for the error messages
}
finally
{
//Q. what is suitable to execute in finally? return the Content(data) here?
if (files != null)
{
//files.Close();
}
}
}
//Q. what to pass on inside of the Ok() in this scenario?
return Ok();
}
}
Q1. How can I check if the POST method has been already triggered, and created the Container? If so how can I get the container name and connect to it?
Q2. Should I give a new assigned name to the chosen file? How can I do so?
Q3. How can I get the chosen file's name so I can pass in order to process Q2?
Q4. How to get the local file path so I can pass on to the FileStream?
Q5. How to return the Content data and pass to the FE? by using fetch('Home').then... like this?
Q6. How can I use storageExeption for the error messages
Q7. What is suitable to execute in finally? return the Content(data) here?
Q8. What to pass on inside of the Ok() in this scenario?
Any help is welcomed! I know I asked a lot of Qs here. Thanks a lot!
Update: add a sample code, you can modify it as per your need.
[HttpPost]
public async Task<IActionResult> SaveFile(List<IFormFile> files)
{
if (files == null || files.Count == 0) return Content("file not selected");
string connectionString = "xxxxxxxx";
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
string containerName = "textdata" + Guid.NewGuid().ToString();;
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
containerClient.CreateIfNotExists();
foreach (var file in files)
{
//use this line of code to get file name
string fileName = Path.GetFileName(file.FileName);
BlobClient blobClient = containerClient.GetBlobClient(fileName);
//directly read file content
using (var stream = file.OpenReadStream())
{
await blobClient.UploadAsync(stream);
}
}
//other code
return View();
}
Original answer:
When using List<IFormFile>, you should use foreach code block to iterate each file in the list.
Q2. Should I give a new assigned name to the chosen file? How can I do
so?
If you want to keep the file original name, in the foreach statement like below:
foreach (var file in myfiles)
{
Path.GetFileName(file.FileName)
//other code
}
And if you want to assign a new file name when uploaded to blob storage, you should define the new name in this line of code: BlobClient blobClient = containerClient.GetBlobClient("the new file name").
Q3. How can I get the chosen file's name so I can pass in order to
process Q2?
refer to Q2.
Q4. How to get the local file path so I can pass on to the FileStream?
You can use code like this: string localFilePath = file.FileName; to get the path, and then combine with the file name. But there is a better way, you can directly use this line of code Stream uploadFileStream = file.OpenReadStream().
Q5. How to return the Content data and pass to the FE? by using
fetch('Home').then... like this?
Not clear what's it meaning. Can you provide more details?
Q6. How can I use storageExeption for the error messages
The storageExeption does not exist in the latest version, you should install the older one.
You can refer to this link for more details.
#Ivan's answer is what the documentation seems the recommend; however, I was having a strange issue where my stream was always prematurely closed before the upload had time to complete. To anyone else who might run into this problem, going the BinaryData route helped me. Here's what that looks like:
await using var ms = new MemoryStream();
await file.CopyToAsync(ms);
var data = new BinaryData(ms.ToArray());
await blobClient.UploadAsync(data);

OutputFileResults returned by OnImageSavedCallback has an invalid Uri

I am using CameraX API to take pictures in my android app, save them and then display them from their path. With the previous version alpha-09 I was able to do so with onImageSaved(File file). However with the alpha-10 I have to use onImageSaved(OutputFileResults outputFileResults) and then get the path from the uri retrieved by the outputFileResults. But the Uri I get is always wrong. For instance when my image is saved at: "/external/images/media/1581680878237.jpg" I get the uri's path: "/external/images/media/113758".
Here is my code:
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "NEW_IMAGE");
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(
activity.getContentResolver(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues).build();
imageCapture.takePicture(outputFileOptions, Runnable::run, new ImageCapture.OnImageSavedCallback() {
#Override
public void onImageSaved(#NonNull ImageCapture.OutputFileResults outputFileResults) {
Uri uri = outputFileResults.getSavedUri();
if(uri != null){
System.out.println("URI PATH" + uri.getPath());
System.out.println("URI PATH" + uri.toString());
activity.runOnUiThread(cameraProvider::unbindAll);
galleryAddPic(uri);
Bundle params = new Bundle();
params.putString("FILE_PATH", uri.getPath());
Navigation.findNavController(root).navigate(R.id.navigation_edit_image, params);
}
}
#Override
public void onError(#NonNull ImageCaptureException exception) {
exception.printStackTrace();
}
});
So I finally managed to save the image taken by ImageCapture by using an other method (especially an other ImageCapture.OutputFileOptions.Builde). I didn't use an Uri object to save the image but a File object.
File mImageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_DIRECTORY");
boolean isDirectoryCreated = mImageDir.exists() || mImageDir.mkdirs();
if(isDirectoryCreated){
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/YOUR_DIRECTORY", "YOUR_IMAGE.jpg");
ImageCapture.OutputFileOptions.Builder outputFileOptionsBuilder =
new ImageCapture.OutputFileOptions.Builder(file);
imageCapture.takePicture(outputFileOptionsBuilder.build(), Runnable::run, new ImageCapture.OnImageSavedCallback() {
#Override
public void onImageSaved(#NonNull ImageCapture.OutputFileResults outputFileResults) {
Bundle params = new Bundle();
params.putString("FILE_PATH", file.getPath());
Navigation.findNavController(root).navigate(R.id.navigation_edit_image, params);
}
#Override
public void onError(#NonNull ImageCaptureException exception) {
exception.printStackTrace();
}
});
}
Be aware that if you use outputFileResults.getSavedUri() with this method you will always have a null uri.
As of CameraX alpha 10, ImageCapture supports 3 types of save location: File, MediaStore URI and OutputStream, depending on which OutputFileOptions.Builder() is used.
The Uri field in OutputFileResults is only populated if the OutputFileOptions is MediaStore URI type. For File type, the caller should have the save location already, there is no need to return the info; for OutputStream type, the save location is unknown to CameraX. See the JavaDoc:
public Uri getSavedUri ()
Returns the Uri of the saved file.
This field is only returned if the ImageCapture.OutputFileOptions is
backed by MediaStore constructed with #Builder(ContentResolver, Uri,
ContentValues).
For more info, please checkout the developer doc.

MVC5 Using Controller to serve images, value can not be null

I'm new to MVC and I followed another tutorial on loading local files to the webpage and while it seems to work for others I am getting an error.
public class ImagesController : Controller
{
// GET: Images
public ActionResult SomeImage(string imageName)
{
var root = #"C:\Images\";
var path = Path.Combine(root, imageName);
path = Path.GetFullPath(path);
if (!path.StartsWith(root))
{
// Ensure that we are serving file only inside the root folder
// and block requests outside like "../web.config"
throw new HttpException(403, "Forbidden");
}
return File(path, "image/png");
}
}
The error I'm getting is:
An exception of type 'System.ArgumentNullException' occurred in mscorlib.dll but was not handled in user code
Additional information: Value cannot be null.
And the line it highlights is:
var path = Path.Combine(root, imageName);
When using Url.Action() helper, the property name in the anonymous object has to match the name of the parameter in the action.
And in your case:
#Url.Action("SomeImage", "Images", new { imageName = "Logo.png" })
As haim770 mentioned, it looks like you are missing the "Name" part of the imageName parameter. You can certainly add error handling to your code in order to localize the exception. This might help you narrow down any coding issues.
if(imageName == null)
{
throw new ArgumentNullException(null, "imageName is NULL");
}

Allowing the user downloading a file located in a specific IIS folder

I have the following issue: ASP-MVC
I want to put a file in a folder in IIS and allow users surfing my site to download it.
In my site, I will have a link that points to an action method in my controller, and within this method I want to put the needed code. Never dealt with this issue before, will appriciate a code sample. Thanks!
This code , taken from this question, will accomplish what you want.
public FileResult Download()
{
byte[] fileBytes = System.IO.File.ReadAllBytes("c:\folder\myfile.ext");
string fileName = "myfile.ext";
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Assuming you want to get a specific file based on some passed-in ID, you can use the Controller.File function as described here: http://msdn.microsoft.com/en-us/library/dd492492(v=vs.100).aspx
Here's an example controller function from that page:
public ActionResult ShowFileFN(string id) {
string mp = Server.MapPath("~/Content/" + id);
return File(mp, "text/html");
}
This will return a binary stream of the named file with the specified MIME content type, in this case "text/html". You'll need to know the MIME type for each file you're returning.
Here's a function to get the MIME type of a file based on its extension:
public static string GetMimeType(string fileName)
{
string mimeType = "application/unknown";
string ext = System.IO.Path.GetExtension(fileName).ToLower();
Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (regKey != null && regKey.GetValue("Content Type") != null)
mimeType = regKey.GetValue("Content Type").ToString();
return mimeType;
}

Resources