Where is the ios LocalStorage when using PCLStorage for Xamarin forms? - xamarin.ios

I am using PCLStorage to store image in localStorage and access them via path returned.
Its working fine but the problem is, whenever I again start debugging the application, images are not accessible.
Where actually it stores images in Local Storage? Is it not permanent location?
I want to store images in fileSystem and related data and image path in sqlite. Its an offline application so need to store this data permanently.
Any suggestions for this would be helpful.
Thanks

Try below steps.
The interface is fairly simple because we're really only interested in passing the byte array and a filename when we save the image to disk.
public interface IPicture
{
void SavePictureToDisk (string filename, byte[] imageData);
}
DependencyService will delegate image saving to the appropriate class. The usage for the DependencyService is:
DependencyService.Get<IPicture>().SavePictureToDisk("ImageName", GetByteArray());
Create Classes in Platform-Specific Projects
iOS Project
[assembly: Xamarin.Forms.Dependency(typeof(Picture_iOS))]
namespace ImageSave.iOS
{
public class Picture_iOS: IPicture
{
public void SavePictureToDisk(string filename, byte[] imageData)
{
var MyImage = new UIImage(NSData.FromArray(imageData));
MyImage.SaveToPhotosAlbum((image, error) =>
{
//you can retrieve the saved UI Image as well if needed using
//var i = image as UIImage;
if(error != null)
{
Console.WriteLine(error.ToString());
}
});
}
}
}

I got the answer for this question on Xamarin Forum so just updating the link here so it can help others.
https://forums.xamarin.com/discussion/comment/217282/#Comment_217282
As explained here that everytime we redeploy app the core path changes thats why on redeploying I was not able to find images on the path where I saved it. So now I am only saving the partial path like the folderName\the image name and rest of the core path I am finding on runtime.
This solved my problem.

Related

setting must be in the form "name=value" in vs 2017

I have been learning the bot framework from microsoft and have been following a tutorial on pluralsight. I have made the changes to my Global.asax.cs and for some reason I keep on getting the error setting must be in the form name=value. I have no idea what to do and how to get rid of these errors. Any help would be highly appreciated.
Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// This code chunk below will allow us to use table bot data store instead of
// in memory data store
Conversation.UpdateContainer(
builder =>
{
builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));
// here we grab the storage container string from our web config and connecting
var store = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
builder.Register(c => store).
Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore).
AsSelf().
SingleInstance();
});
GlobalConfiguration.Configure(WebApiConfig.Register);
TableBotDataStore is for Azure Table Storage, and it seems you are using some sql connectionstring. You would usually have that connection string in the AppSettings section, not the ConnectionStrings section (yes, the names are a bit misguiding here).

How to store file into inetpub\wwwroot instead of local machine folder on UWP application

I am currently developing a UWP application for my school project and one of the pages allows the user to take a picture of themselves. I created the feature by following this tutorial: CameraStarterKit
For now I am storing the pictures taken on my desktop's picture folder. But the requirement of my project is to store the pictures taken in a folder called "Photos" under inetpub\wwwroot.
I dont really understand what wwwroot or IIS is... hence, I have no idea how I should modify my codes and store them into the folder.
Here are my codes for storing on my local desktop:
private async Task TakePhotoAsync()
{
idleTimer.Stop();
idleTimer.Start();
var stream = new InMemoryRandomAccessStream();
//MediaPlayer mediaPlayer = new MediaPlayer();
//mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/camera-shutter-click-03.mp3"));
//mediaPlayer.Play();
Debug.WriteLine("Taking photo...");
await _mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), stream);
try
{
var file = await _captureFolder.CreateFileAsync("NYPVisitPhoto.jpg", CreationCollisionOption.GenerateUniqueName);
Debug.WriteLine("Photo taken! Saving to " + file.Path);
var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(_rotationHelper.GetCameraCaptureOrientation());
await ReencodeAndSavePhotoAsync(stream, file, photoOrientation);
Debug.WriteLine("Photo saved!");
}
catch (Exception ex)
{
// File I/O errors are reported as exceptions
Debug.WriteLine("Exception when taking a photo: " + ex.ToString());
}
}
For the storing of the files:
private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation)
{
using (var inputStream = stream)
{
var decoder = await BitmapDecoder.CreateAsync(inputStream);
using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
await encoder.BitmapProperties.SetPropertiesAsync(properties);
await encoder.FlushAsync();
}
}
}
I would add an answer since there are tricky things about this requirement.
The first is the app can only access a few folders, inetpub is not one of them.
Using brokered Windows runtime component (I would suggest using FullTrustProcessLauncher, which is much simpler to develop and deploy) can enable UWP apps access folders in the same way as the traditional desktop applications do.
While this works for an ordinary folder, the inetpub folder, however, is different that it requires Administrators Privileges to write to, unless you turn UAC off.
The desktop component launched by the app does not have the adequate privileges to write to that folder, either.
So it think an alternative way would be setting up a virtual directory in IIS manager that maps to a folder in the public Pictures library, and the app saves picture to that folder.
From the website’s perspective, a virtual directory is the same as a real folder under inetpub, what differs is the access permissions.
Kennyzx is right here that you cannot access inetpub folder through your UWP application due to permissions.
But if your application fulfills following criteria then you can use Brokered Windows Component(a component within your app) to copy your file to any location in the system.
Your application is a LOB application
You are only targetting desktop devices(I assume this will be true because of your requirement)
You are using side-loading for your app installation and distribution.
If all three are Yes then use Brokered Windows Component for UWP, it's not a small thing that can be showed here on SO using an example. So give worth a try reading and implementing it.

Why am I getting "A route named 'swagger_docs' is already in the route collection" after I publish my API App?

After publishing my API App I'm getting the yellow error screen of ASP.NET. The error message says "A route named 'swagger_docs' is already in the route collection".
How can I fix this?
This is not related to API Apps per se but more around Web API. What triggers the error is pretty simple:
You publish the API App which is based on Web API.
You discard your project and start working on a new API App based on Web API
You want to publish the new API App instead of the old API App you created at step 1.
You select the API App during "Publish.." and you get the publishing profile of the existing API App we deployed at step 1.
You deploy using Web Deploy and the publishing profile, the new API App on top of the old one.
That will trigger the issue I've explained before. That happens because there are two routes being registered by Swashbuckle when you try to start the app. One of the old one and one of the new one. That's because the old files are still present at the destination.
To solve this, during Web Deploy, click on the Settings tab and then expand the "File Publish Options". There is a checkbox there, called "Remove additional files from destination". This will fix the issue as it will only leave the files you deploy at the destination and not the old ones as well.
Hope it helps.
What if it happens when trying to debug the app locally ?
This happened for me, and the reason was, I renamed my assembly name. So the bin folder had two dlls for the same project with different names which caused this error. Once I deleted the old named dll all is well. Hope this helps.
This happens because You probally are configuring you route in your WebApiConfig class and SwaggerConfig class, as explained below:
WebApiConfig file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
SwaggerConfig.Register();
}
}
SwaggerConfig file:
using Swashbuckle.Application;
[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
namespace NEOH.Api
{
public class SwaggerConfig
{
public static void Register()
{
What you should do is remove the assembly call on SwaggerConfig file.
It should work.
My Solution & Cause:
I had the same problem when I renamed NamesSpaces,Refactored,etc.
After reading what everyone else did here's what I tried:
Cleaned the Solution in Visual Studio
Cleaned the Bin folder manually
Checked the nameSpace in the Project Properties (copied it just in case) >> Build tab >> Scrolldown to Output and ensure the XML documentation file is correct. You will need this name later.
Opened up: SwaggerConfig.cs >> fixed the name space in here (copy,paste) c.SingleApiVersion("vX","NameSpace")
Scrolled down until I found: GetXmlCommentsPath() copied and pasted the correct name space in the .xml file path.
Ran, smoke tested, finished this post.
My issue was that I was referencing another project that had the Swashbuckle extension.
Here is how I kept both projects without changing the anything in project that was referenced:
Remove the routes created by the project referenced under SwaggerConfig.cs > Register right before GlobalConfiguration.Configuration.EnableSwagger(...).EnableSwaggerUi(...);:
// Clears the previous routes as this solution references another Swagger ASP.NET project which adds the swagger routes.
// Trying to add the Swagger routes more than once will prevent the application from starting
GlobalConfiguration.Configuration.Routes.Clear();
Then, the application will be able to start, but you will see the operations/functions that are in both projects. To remove the operations from the project being referenced...
Create the following class
using Swashbuckle.Swagger;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Description;
namespace yournamespace.Models
{
/// <summary>
/// This class allows to manage the Swagger document filters.
/// </summary>
public class SwaggerCustomOperationsFilter : IDocumentFilter
{
/// <summary>
/// Applies the Swagger operation filter to exclude the Swagger operations/functions
/// that are inherited by the other Swagger projects referenced.
/// </summary>
///
/// <param name="p_swaggerDoc">Swagger document</param>
/// <param name="p_schemaRegistry">Swagger schema registry</param>
/// <param name="p_apiExplorer">Api description collection</param>
public void Apply(SwaggerDocument p_swaggerDoc, SchemaRegistry p_schemaRegistry, IApiExplorer p_apiExplorer)
{
IEnumerable<ApiDescription> externalApiDescriptions = p_apiExplorer.ApiDescriptions
.Where(d => d.ActionDescriptor.ControllerDescriptor.ControllerType.Module.Name != GetType().Module.Name);
IEnumerable<int> externalApiDescriptionIndexes = externalApiDescriptions
.Select(d => p_apiExplorer.ApiDescriptions.IndexOf(d))
.OrderByDescending(i => i);
IEnumerable<string> externalPaths = externalApiDescriptions.Select(d => $"/{d.RelativePathSansQueryString()}");
foreach (string path in externalPaths)
{
p_swaggerDoc.paths.Remove(path);
}
foreach (int apiDescriptionIndex in externalApiDescriptionIndexes)
{
p_apiExplorer.ApiDescriptions.RemoveAt(apiDescriptionIndex);
}
}
}
}
And add the following in SwaggerConfig.cs > Register > GlobalConfiguration.Configuration.EnableSwagger(...)
c.DocumentFilter<SwaggerCustomOperationsFilter>();
Alternative cause of this problem:
Seems like a lot of people have this issue resolved by deleting their "bin" and "obj" folders as per the other answers.
However the cause of the issue might be that you are configuring your Swagger Config in a referenced project, as per this comment: https://github.com/domaindrivendev/Swashbuckle/issues/364#issuecomment-226013593
I received this error when one project with Swagger referenced another
project with Swagger. Removing the reference fixed the problem.
This caused me to split some core functionality out into a Third project that both of my API's could reference, rather than them referencing each other.

Where to keep p12 file securely on App Engine?

On App Engine, I need a p12 file to create signed URLs:
https://developers.google.com/storage/docs/accesscontrol#Signing-Strings
Google does not describe what are best practices about keeping this file.
Can I use the WEB-INF directory to store the file? It would then be part of the source code and kept together with the password to open it.
What are best practices here? Or other approaches?
--
What about performance? Is it efficient to load the file over and over again? Does App Engine automatically cache the file across calls (on the same instance)? Or will I need to load the file once using a servlet and then keep it in a static variable somehow? Are there better ways to achieve this, like storing the file in a datastore record and then keep it in memcache? How secure would that approach be? Probably no good, right?
In App Engine specifically there are a number of unusual security limitations around File storage. I have found the best place to store resources securely is by using the bundle itself. If you're using the default Maven setup as produced by the appengine maven skeleton project this is as simple as placing the file inside of the appropriate resources directory
Once the p12 is in the correct location, you'll need to load it using the class loader's GetResourceAsStream function. Then when building the GoogleCredentials, don't use the documented setServiceAccountPrivateKeyFromP12File() function, but instead use the setServiceAccountPrivateKey() function and pass in the PrivateKey that you just constructed.
Additionally, you will most likely not want to use any of this functionality with a live appengine instance since Appengine already provides you with a much easier to use AppIdentityCredentials function in that case so you will probably want to detect whether or not your app is in production mode and only use the ServiceAccount when testing using localhost.
Putting all of these functions together yields the following function which works for me:
public static HttpRequestInitializer getDefaultCredentials() throws IOException
{
List<String> scopes = Arrays.asList(new String[] {DEVSTORAGE_FULL_CONTROL});
if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Production)
return new AppIdentityCredential(scopes);
else
{
GoogleCredential credential;
try {
String p12Password = "notasecret";
ClassLoader classLoader = ServiceUtils.class.getClassLoader();
KeyStore keystore = KeyStore.getInstance("PKCS12");
InputStream keyFileStream = classLoader.getResourceAsStream("key.p12");
if (keyFileStream == null){
throw new Exception("Key File Not Found.");
}
keystore.load(keyFileStream, p12Password.toCharArray());
PrivateKey key = (PrivateKey)keystore.getKey("privatekey", p12Password.toCharArray());
credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("YOUR_SERVICE_ACCOUNT_EMAIL#developer.gserviceaccount.com")
.setServiceAccountPrivateKey(key)
.setServiceAccountScopes(scopes)
.build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
return credential;
}
}

Upload a file to SharePoint through the built-in web services

What is the best way to upload a file to a Document Library on a SharePoint server through the built-in web services that version WSS 3.0 exposes?
Following the two initial answers...
We definitely need to use the Web Service layer as we will be making these calls from remote client applications.
The WebDAV method would work for us, but we would prefer to be consistent with the web service integration method.
There is additionally a web service to upload files, painful but works all the time.
Are you referring to the “Copy” service?
We have been successful with this service’s CopyIntoItems method. Would this be the recommended way to upload a file to Document Libraries using only the WSS web service API?
I have posted our code as a suggested answer.
Example of using the WSS "Copy" Web service to upload a document to a library...
public static void UploadFile2007(string destinationUrl, byte[] fileData)
{
// List of desination Urls, Just one in this example.
string[] destinationUrls = { Uri.EscapeUriString(destinationUrl) };
// Empty Field Information. This can be populated but not for this example.
SharePoint2007CopyService.FieldInformation information = new
SharePoint2007CopyService.FieldInformation();
SharePoint2007CopyService.FieldInformation[] info = { information };
// To receive the result Xml.
SharePoint2007CopyService.CopyResult[] result;
// Create the Copy web service instance configured from the web.config file.
SharePoint2007CopyService.CopySoapClient
CopyService2007 = new CopySoapClient("CopySoap");
CopyService2007.ClientCredentials.Windows.ClientCredential =
CredentialCache.DefaultNetworkCredentials;
CopyService2007.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Delegation;
CopyService2007.CopyIntoItems(destinationUrl, destinationUrls, info, fileData, out result);
if (result[0].ErrorCode != SharePoint2007CopyService.CopyErrorCode.Success)
{
// ...
}
}
Another option is to use plain ol' HTTP PUT:
WebClient webclient = new WebClient();
webclient.Credentials = new NetworkCredential(_userName, _password, _domain);
webclient.UploadFile(remoteFileURL, "PUT", FilePath);
webclient.Dispose();
Where remoteFileURL points to your SharePoint document library...
There are a couple of things to consider:
Copy.CopyIntoItems needs the document to be already present at some server. The document is passed as a parameter of the webservice call, which will limit how large the document can be. (See http://social.msdn.microsoft.com/Forums/en-AU/sharepointdevelopment/thread/e4e00092-b312-4d4c-a0d2-1cfc2beb9a6c)
the 'http put' method (ie webdav...) will only put the document in the library, but not set field values
to update field values you can call Lists.UpdateListItem after the 'http put'
document libraries can have directories, you can make them with 'http mkcol'
you may want to check in files with Lists.CheckInFile
you can also create a custom webservice that uses the SPxxx .Net API, but that new webservice will have to be installed on the server. It could save trips to the server.
public static void UploadFile(byte[] fileData) {
var copy = new Copy {
Url = "http://servername/sitename/_vti_bin/copy.asmx",
UseDefaultCredentials = true
};
string destinationUrl = "http://servername/sitename/doclibrary/filename";
string[] destinationUrls = {destinationUrl};
var info1 = new FieldInformation
{
DisplayName = "Title",
InternalName = "Title",
Type = FieldType.Text,
Value = "New Title"
};
FieldInformation[] info = {info1};
var copyResult = new CopyResult();
CopyResult[] copyResults = {copyResult};
copy.CopyIntoItems(
destinationUrl, destinationUrls, info, fileData, out copyResults);
}
NOTE: Changing the 1st parameter of CopyIntoItems to the file name, Path.GetFileName(destinationUrl), makes the unlink message disappear.
I've had good luck using the DocLibHelper wrapper class described here: http://geek.hubkey.com/2007/10/upload-file-to-sharepoint-document.html
From a colleage at work:
Lazy way: your Windows WebDAV filesystem interface. It is bad as a programmatic solution because it relies on the WindowsClient service running on your OS, and also only works on websites running on port 80. Map a drive to the document library and get with the file copying.
There is additionally a web service to upload files, painful but works all the time.
I believe you are able to upload files via the FrontPage API but I don’t know of anyone who actually uses it.
Not sure on exactly which web service to use, but if you are in a position where you can use the SharePoint .NET API Dlls, then using the SPList and SPLibrary.Items.Add is really easy.

Resources