I have a Xamarin mobile project setup with the Sitecore MobileSDK (WebAPI) and can browse through the items using the ReadItemsRequestWithPath method. Now I am trying to download a pdf file that is stored in the 'media library' directory. I have tried the following:
private async void DownloadFile()
{
try
{
string instanceUrl = "https://sitecoredev10.myapp.org";
using (var demoCredentials = new SecureStringPasswordProvider("username", "password"))
using
(
var session =
SitecoreWebApiSessionBuilder.AuthenticatedSessionWithHost(instanceUrl)
.Credentials(demoCredentials)
.BuildReadonlySession())
{
var request = ItemWebApiRequestBuilder.DownloadResourceRequestWithMediaPath("/sitecore/media library/path/to/file")
.Build();
Stream response = await session.DownloadMediaResourceAsync(request);
// Process Stream...
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
Exception originalError = e.InnerException;
Console.WriteLine(originalError.Message); // access original error
Console.WriteLine(originalError.StackTrace);
}
}
However, I'm getting the following exception:
[Sitecore Mobile SDK] Unable to download data from the internet
2016-11-03 15:24:53.411 SitecoreDemo.iOS[88136:15581600] Not Found
Should I be using a different method other than DownloadMediaResourceAsync? How can I download the file?
Related
I wrote a program using CSOM to upload documents to SharePoint and insert metadata to the properties. once a while(like every 3 months) the SharePoint server gets busy or we reset IIS or any other communication problem that it may have, we get "The operation has timed out" error on clientContext.ExecuteQuery(). To resolve the issue I wrote an extension method for ExecuteQuery to try every 10 seconds for 5 times to connect to the server and execute the query. My code works in the Dev and QA environment without any problem but in Prod, when it fails the first time with timeout error, in the second attempt, it only uploads the document but it doesn't update the properties and all the properties are empty in the library. It doesn't return any error as result of ExecteQuery() but It seems from the two requests in the batch witch are uploading the file and updating the properties, it just does uploading and I don't know what happens to the properties. It kinda removes that from the batch in the second attempt!
I used both upload methods docs.RootFolder.Files.Add and File.SaveBinaryDirect in different parts of my code but I copy just one of them here so you can see what I have in my code.
I appreciate your help.
public static void ExecuteSharePointQuery(ClientContext context)
{
int cnt = 0;
bool isExecute = false;
while (cnt < 5)
{
try
{
context.ExecuteQuery();
isExecute = true;
break;
}
catch (Exception ex)
{
cnt++;
Logger.Error(string.Format("Communication attempt with SharePoint failed. Attempt {0}", cnt));
Logger.Error(ex.Message);
Thread.Sleep(10000);
if (cnt == 5 && isExecute == false)
{
Logger.Error(string.Format("Couldn't execute the query in SharePoint."));
Logger.Error(ex.Message);
throw;
}
}
}
}
public static void UploadSPFileWithProperties(string siteURL, string listTitle, FieldMapper item)
{
Logger.Info(string.Format("Uploading to SharePoint: {0}", item.pdfPath));
using (ClientContext clientContext = new ClientContext(siteURL))
{
using (FileStream fs = new FileStream(item.pdfPath, FileMode.Open))
{
try
{
FileCreationInformation fileCreationInformation = new FileCreationInformation();
fileCreationInformation.ContentStream = fs;
fileCreationInformation.Url = Path.GetFileName(item.pdfPath);
fileCreationInformation.Overwrite = true;
List docs = clientContext.Web.Lists.GetByTitle(listTitle);
Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(fileCreationInformation);
uploadFile.CheckOut();
//Update the metadata
ListItem listItem = uploadFile.ListItemAllFields;
//Set field values on item
foreach (List<string> list in item.fieldMappings)
{
if (list[FieldMapper.SP_VALUE_INDEX] != null)
{
TrySet(ref listItem, list[FieldMapper.SP_FIELD_NAME_INDEX], (FieldType)Enum.Parse(typeof(FieldType), list[FieldMapper.SP_TYPE_INDEX]), list[FieldMapper.SP_VALUE_INDEX]);
}
}
listItem.Update();
uploadFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
SharePointUtilities.ExecuteSharePointQuery(clientContext);
}
catch (Exception ex)
{
}
}
}
}
There's too many possible reasons for me to really comment on a solution, especially considering it's only on the prod environment.
What I can say is that it's probably easiest to keep a reference to the last uploaded file. If your code fails then check if the last file has been uploaded correctly.
Side note: I'm not sure if this is relevant but if it's a large file you want to upload it in slices.
I used google.cloud.storage for .mp3 files. I tried it before and it worked.
now I writed another new function that uses the existing storage function.
everything was suppose to work but I get this weird error:
"Google.Apis.Requests.RequestError
text-to-speach#XXXXXXXXXXX.iam.gserviceaccount.com does not have storage.objects.create access to objectsound/voiceAnimals20.mp3. [403]"
I dont know what to begin with. can anybody help me?
the Ok storage function is here:
public static string VoiceStorage(int catId, string URL,
Dictionary<string, int> voicesCounter)
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
#"C:\wordproject-XXXXXXXXXX.json");
// upload the image storage
//----------------
string voiceName;
voiceName = "voice" + BLLcategory.GetCategoryById(catId).CategoryName
+ voicesCounter[BLLcategory.GetCategoryById(catId).CategoryName]++ +
".mp3";
string bucketName = "XXXXXXXX";
var storage = StorageClient.Create();
using (var f = File.OpenRead(URL))
{
try
{
var res = storage.UploadObject(bucketName, voiceName, null,
f);
URL = "https://storage.cloud.google.com/" + bucketName + "/" +
voiceName;
}
catch (Exception e)
{
throw e;
}
}
return URL;
}
the new not working function is:
private void button12_Click(object sender, EventArgs e)
{
foreach (COMimageObject obj in BLLobject.GetObjects())
{
if(obj.VoiceURL==null)
{
try
{
string url=BLLtextToSpeach.TextToSpeach(obj.Name);
url=BLLtextToSpeach.VoiceStorage(
BLLimage.GetImageById(obj.ImageID).CategoryID,
url, voicesCounter);
BLLobject.UpdateVoiceURL(obj.ObjectId, url);
}
catch (Exception)
{
throw;
}
}
}
}
the catch happening after the line with url=BLLtextToSpeach.VoiceStorage
tnx!!
What the error mean is that the service account of the text-to-speach api doesn't have create access on the objectsound bucket. Go to the bucket permissions and add the text-to-speach service account with storage creator rights.
When you get this error:
[403] Errors [ Message[.................iam.gserviceaccount.com does
not have storage.buckets.list access to the Google Cloud project.
you need to have permissions in your service account from the IAM to read the buckets
storage.buckets.get Read bucket metadata, excluding IAM policies.
storage.buckets.list List buckets in a project. Also read bucket
metadata,
https://cloud.google.com/storage/docs/access-control/iam-permissions
The "Firebase Admin" will enable all necessary permissions.
I am uploading files to dropbox using the following code.
I am using the nuget package Dropbox.Api and getting the exception System.Threading.Tasks.TaskCanceledException("A task was canceled.")
From this SO Question it appears to be a timeout issue.
So how do I modify the following code to set the timeout.
public async Task<FileMetadata> UploadFileToDropBox(string fileToUpload, string folder)
{
DropboxClient client = new DropboxClient(GetAccessToken());
using (var mem = new MemoryStream(File.ReadAllBytes(fileToUpload)))
{
string filename = Path.GetFileName(fileToUpload);
try
{
string megapath = GetFullFolderPath(folder);
string megapathWithFile = Path.Combine(megapath, Path.GetFileName(Path.GetFileName(filename))).Replace("\\", "/");
var updated = client.Files.UploadAsync(megapathWithFile, WriteMode.Overwrite.Instance, body: mem);
await updated;
return updated.Result;
}
catch (Exception ex)
{
return null;
}
}
}
Try creating and initializing the client like this:
var config = new DropboxClientConfig();
config.HttpClient.Timeout = new TimeSpan(hr, min, sec); // choose values
var client = DropboxClient(GetAccessToken(), config);
Reference:
http://dropbox.github.io/dropbox-sdk-dotnet/html/M_Dropbox_Api_DropboxClient__ctor_1.htm
One more thing to keep in mind is UploadAsync will not work for files larger than 150MB as per documentation. One will have to use UploadSessionStartAsync based implementation for it. I was making the mistake without realizing it and it took ages for me to fish the problem out.
The below code an attempt to try and get get an Mp3 file from the MusicLibrary
It gives me,
A first chance exception of type
'System.UnauthorizedAccessException'
occurred in AccessingPictures.exe
This is my code:
public async void getFile()
{
StorageFolder folder = KnownFolders.MusicLibrary;
try
{
sampleFile = await folder.GetFileAsync("Test1.mp3");
}
catch (FileNotFoundException e)
{
// If file doesn't exist, indicate users to use scenario 1
Debug.WriteLine(e);
}
}
private void btnRead_Click(object sender, RoutedEventArgs e)
{
getFile();
}
Wouldn't we able to access the media files?
I am able to do this using the file picker.
But it does not work while i try to access it directly.
Am i missing anything here ?
To retrieve Pictures from Camera Roll
Void GetCameraPhotos()
{
using (var library = new MediaLibrary())
{
PictureAlbumCollection allAlbums = library.RootPictureAlbum.Albums;
PictureAlbum cameraRoll = allAlbums.Where(album => album.Name == "Camera Roll").FirstOrDefault();
var CameraRollPictures = cameraRoll.Pictures
}
}
You cannot access the files unless it is in response to a user request. i.e. the user must tap a button or something and that tap logic ends up calling your code that accesses the file. If you want to get at the file afterwards, you'll need to copy it in the app's data folder.
I finally figured the issue. It was because i hadn't enabled the capabilities in the Manifest file.
It works like a charm now.
Thanks everyone.
I have the following code where I'm trying to download 3 different files from the users SkyDrive Account.
I'm using the SkyDrive API for Windows Phone development.
client.DownloadCompleted += new EventHandler<LiveDownloadCompletedEventArgs>(OnDownloadCompletedVI);
client.DownloadAsync(fileIdVehicleItems);
client.DownloadCompleted += new EventHandler<LiveDownloadCompletedEventArgs>(OnDownloadCompletedHI);
client.DownloadAsync(fileIdHistoryItems);
client.DownloadCompleted += new EventHandler<LiveDownloadCompletedEventArgs>(OnDownloadCompletedRI);
client.DownloadAsync(fileIdRepairItems);
When I run this, the only method that gets called is the OnDownloadCompletedVI. All the files that are being downloaded are running through this method which is causing an error.
What am I doing incorrectly?
Update
I have the following method, but I have 2 other similar methods that do the exact same thing except it loads different objects (based off of the downloaded files).
The error I'm currently receiving:
An exception of type 'System.ArgumentException' occurred in
mscorlib.ni.dll but was not handled in user code
void OnDownloadCompletedVI(object sender, LiveDownloadCompletedEventArgs e)
{
if (e.Result != null)
{
using (var stream_vi = e.Result)
{
StreamReader SRVI = new StreamReader(stream_vi);
string contentVI = "";
contentVI = SRVI.ReadToEnd();
StringReader rdr_vi = new StringReader(contentVI);
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<vehicle>));
ObservableCollection<vehicle> importedVehicles = new ObservableCollection<vehicle>();
importedVehicles = (ObservableCollection<vehicle>)serializer.Deserialize(rdr_vi);
StorageHelper.Save<ObservableCollection<vehicle>>(App.vehicleData, importedVehicles);
}
//e.Result.Close();
}
else
{
infoTextBlock.Text = "Error downloading file: " + e.Error.ToString();
}
}
Actually all three methods should be called. Of course, if the first method is called and throws an exception the other two won't trigger.
What you can do is either create a new client for each call, or download them in order, so when the OnDownloadCompletedVI method is complete, remove the event handler for OnDownloadCompletedVI and add the one for OnDownloadCompletedHI and then trigger the client.DownloadAsync(fileIdHistoryItems); at the end of the method.