Replacing Files in Google Drive UpdateMediaUpload - c#

I have no idea, why the content of the file will not be updated. Has anybody a hint?
The DriveFile.Id is valid. The source File is existing readable. Creating and deleting of files works fine. But not the Update.
I have read the migration from v2 to v3 uses generell the Http-PATCH Method for Update. Is this the answer.
I don't want to delete the file and create a new one.
public long DriveUpdateFile(string fileID, string filename, string description, string parent, string mimeType)
{
int lError = (int)Win32ErrorCode.ERROR_SUCCESS;
if (System.IO.File.Exists(filename))
{
FilesResource.GetRequest get = m_Drive.Files.Get(fileID);
File body = get.Execute();
if(!string.IsNullOrEmpty(description))
body.Description = description;
if (!string.IsNullOrEmpty(mimeType))
body.MimeType = mimeType;
// v3 Sematics
if (!string.IsNullOrEmpty(parent))
{
body.Parents = new List<string>();
body.Parents.Add(parent);
}
try
{
// File's content.
using (System.IO.FileStream sr = System.IO.File.OpenRead(filename))
{
FilesResource.UpdateMediaUpload request = m_Drive.Files.Update(body, body.Id, sr, body.MimeType);
request.Upload();
}
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
lError = e.HResult;
}
}
else
{
Console.WriteLine("File does not exist: " + filename);
lError = (int)Win32ErrorCode.ERROR_FILE_NOT_FOUND;
}
return (lError);
}

Use scopes as below,
string[] scopes = new string[] {
DriveService.Scope.Drive,
DriveService.Scope.DriveFile,
DriveService.Scope.DriveMetadata,
DriveService.Scope.DriveAppdata,
DriveService.Scope.DriveScripts
};//DriveService.Scope.DriveReadonly
and I check above code. the problem is ParentFolderId. please remove this line
body.Parents = new List<string>();
body.Parents.Add(parent);
direct assignment is not allowed in this scope. it should mention with request object like : request.Parent ... bla bla
and try.

Related

GetFileByServerRelativePath does not work and always returns file not found

I was previously using the GetFileByServerRelativeUrl and it was working fine, but the characters # and % are not supported while they are supposed to be supported with GetFileByServerRelativePath, so I changed the code as per below but now it just doesn't work with any files???
public bool DownloadFile(string filepath, out string Base64EncodedFile, out string errormessage)
{
Base64EncodedFile = string.Empty;
errormessage = string.Empty;
try
{
Uri filename = new Uri(filepath);
string serverrelative = filename.AbsolutePath;
//This old method does not support # or % but works fine
//Microsoft.SharePoint.Client.File file = context.Web.GetFileByServerRelativeUrl(serverrelative);
// >> Replaced with this
ResourcePath filePathDecoded = ResourcePath.FromDecodedUrl(serverrelative);
Microsoft.SharePoint.Client.File file = context.Web.GetFileByServerRelativePath(filePathDecoded);
// << Replaced with this
context.Load(file);
ClientResult<System.IO.Stream> streamResult = file.OpenBinaryStream();
context.ExecuteQuery();
Base64EncodedFile = ConvertToBase64(streamResult.Value);
return true;
}
catch (Exception ex)
{
errormessage = ex.Message;
return false;
}
}
SharepointClient.SharepointClient newupload = new SharepointClient.SharepointClient("https://xxxxxxx.sharepoint.com/sites/xxxxxxxxx/", usernametext.Text, textpassword.Text);
newupload.DownloadFile(Url.Text, out EncodedAbs, out errormessage);
If I use the old GetFileByServerRelativeUrl it works just fine... I tried everything but I cannot seem to get to work the GetFileByServerRelativePath ... I can't understand what I'm doing wrong???
Please help!!!
My test code for your reference.
using (ClientContext ctx = new ClientContext(targetSiteURL))
{
ctx.Credentials = onlineCredentials;
string fileName = "FileWith#%.docx";
var _File = ctx.Web.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl($"/sites/lee/MyDoc/{fileName}"));
ctx.Load(_File);
ctx.ExecuteQuery();
Console.Write(_File.ServerRelativeUrl);
Console.WriteLine();
}

Upload file to folder or subfolder on Sharepoint

Im trying to create a method to upload a file stream to a sharepoint so far i have this
public static void SPUploadFileStream(string username, string filePath, Stream fileData)
{
//string siteUrl = Configuration.SPSiteURL;
string siteUrl = SPContext.Current.Web.Url;
SPUser currentUser = SPUtils.GetCurrentUser(username);
if (currentUser == null)
{
throw new SPGappUnknownUserException(username);
}
using (SPSite site = new SPSite(siteUrl, currentUser.UserToken))
{
using (SPWeb web = site.OpenWeb())
{
bool allowWebUnsafeUpdt = web.AllowUnsafeUpdates;
if (!allowWebUnsafeUpdt)
web.AllowUnsafeUpdates = true;
try
{
SPCreateFolder(Path.GetDirectoryName(filePath), username);
SPFile newFile = web.Files.Add(filePath, fileData, true); //true = replace
}
catch (Exception ex)
{
LoggingService.LogError(ex);
//site.AllowUnsafeUpdates = allowSiteUnsefaUpdt;
web.AllowUnsafeUpdates = allowWebUnsafeUpdt;
throw new ApplicationException("ERROR "+ ex.ToString());
}
}
}
}
but it works ok if i have a path like "FOLDER/file.jpg" but it doesn't when i have subfolders "FOLDER/SUB/file.jpg"
can anyone give me some pointers?
My guess is that the problem lies inside your SPCreateFolder method. It should have created folders recursively. As when the you try to add new file with
SPFile newFile = web.Files.Add(filePath, fileData, true); //true = replace
the server relative path must exist. Try following method for folder creation
private static void SPCreateFolder(SPWeb web, string filepath)
{
// since you pass this as Path.GetDictionary it's no longer split by '/'
var foldersTree = filepath.Split('\\');
foldersTree.Aggregate(web.RootFolder, GetOrCreateSPFolder);
}
private static SPFolder GetOrCreateSPFolder(SPFolder sourceFolder, string folderName)
{
SPFolder destination;
try
{
// return the existing SPFolder destination if already exists
destination = sourceFolder.SubFolders[folderName];
}
catch
{
// Create the folder if it can't be found
destination = sourceFolder.SubFolders.Add(folderName);
}
return destination;
}
Then you can execute this with
...
SPCreateFolder(web, Path.GetDirectoryName(filePath));
SPFile newFile = web.Files.Add(filePath, fileData, true); //true = replace
...
Let me know if that helps

C# Upload whole directory using FTP

What I'm trying to do is to upload a website using FTP in C# (C Sharp). So I need to upload all files and folders within a folder, keeping its structure. I'm using this FTP class: http://www.codeproject.com/Tips/443588/Simple-Csharp-FTP-Class for the actual uploading.
I have come to the conclusion that I need to write a recursive method that goes through every sub-directory of the main directory and upload all files and folders in it. This should make an exact copy of my folder to the FTP. Problem is... I have no clue how to write a method like that. I have written recursive methods before but I'm new to the FTP part.
This is what I have so far:
private void recursiveDirectory(string directoryPath)
{
string[] filePaths = null;
string[] subDirectories = null;
filePaths = Directory.GetFiles(directoryPath, "*.*");
subDirectories = Directory.GetDirectories(directoryPath);
if (filePaths != null && subDirectories != null)
{
foreach (string directory in subDirectories)
{
ftpClient.createDirectory(directory);
}
foreach (string file in filePaths)
{
ftpClient.upload(Path.GetDirectoryName(directoryPath), file);
}
}
}
But its far from done and I don't know how to continue. I'm sure more than me needs to know this! Thanks in advance :)
Ohh and... It would be nice if it reported its progress too :) (I'm using a progress bar)
EDIT:
It might have been unclear... How do I upload a directory including all sub-directories and files with FTP?
Problem Solved! :)
Alright so I managed to write the method myslef. If anyone need it feel free to copy:
private void recursiveDirectory(string dirPath, string uploadPath)
{
string[] files = Directory.GetFiles(dirPath, "*.*");
string[] subDirs = Directory.GetDirectories(dirPath);
foreach (string file in files)
{
ftpClient.upload(uploadPath + "/" + Path.GetFileName(file), file);
}
foreach (string subDir in subDirs)
{
ftpClient.createDirectory(uploadPath + "/" + Path.GetFileName(subDir));
recursiveDirectory(subDir, uploadPath + "/" + Path.GetFileName(subDir));
}
}
It works very well :)
I wrote an FTP classe and also wrapped it in a WinForms user control. You can see my code in the article An FtpClient Class and WinForm Control.
I wrote a reusable class to upload entire directory to an ftp site on windows server, the program also renames the old version of that folder (i use it to upload my windows service program to the server).
maybe some need this:
class MyFtpClient
{
protected string FtpUser { get; set; }
protected string FtpPass { get; set; }
protected string FtpServerUrl { get; set; }
protected string DirPathToUpload { get; set; }
protected string BaseDirectory { get; set; }
public MyFtpClient(string ftpuser, string ftppass, string ftpserverurl, string dirpathtoupload)
{
this.FtpPass = ftppass;
this.FtpUser = ftpuser;
this.FtpServerUrl = ftpserverurl;
this.DirPathToUpload = dirpathtoupload;
var spllitedpath = dirpathtoupload.Split('\\').ToArray();
// last index must be the "base" directory on the server
this.BaseDirectory = spllitedpath[spllitedpath.Length - 1];
}
public void UploadDirectory()
{
// rename the old folder version (if exist)
RenameDir(BaseDirectory);
// create a parent folder on server
CreateDir(BaseDirectory);
// upload the files in the most external directory of the path
UploadAllFolderFiles(DirPathToUpload, BaseDirectory);
// loop trough all files in subdirectories
foreach (string dirPath in Directory.GetDirectories(DirPathToUpload, "*",
SearchOption.AllDirectories))
{
// create the folder
CreateDir(dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory)));
Console.WriteLine(dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory)));
UploadAllFolderFiles(dirPath, dirPath.Substring(dirPath.IndexOf(BaseDirectory), dirPath.Length - dirPath.IndexOf(BaseDirectory))
}
}
private void UploadAllFolderFiles(string localpath, string remotepath)
{
string[] files = Directory.GetFiles(localpath);
// get only the filenames and concat to remote path
foreach (string file in files)
{
// full remote path
var fullremotepath = remotepath + "\\" + Path.GetFileName(file);
// local path
var fulllocalpath = Path.GetFullPath(file);
// upload to server
Upload(fulllocalpath, fullremotepath);
}
}
public bool CreateDir(string dirname)
{
try
{
WebRequest request = WebRequest.Create("ftp://" + FtpServerUrl + "/" + dirname);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Proxy = new WebProxy();
request.Credentials = new NetworkCredential(FtpUser, FtpPass);
using (var resp = (FtpWebResponse)request.GetResponse())
{
if (resp.StatusCode == FtpStatusCode.PathnameCreated)
{
return true;
}
else
{
return false;
}
}
}
catch
{
return false;
}
}
public void Upload(string filepath, string targetpath)
{
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential(FtpUser, FtpPass);
client.Proxy = null;
var fixedpath = targetpath.Replace(#"\", "/");
client.UploadFile("ftp://" + FtpServerUrl + "/" + fixedpath, WebRequestMethods.Ftp.UploadFile, filepath);
}
}
public bool RenameDir(string dirname)
{
var path = "ftp://" + FtpServerUrl + "/" + dirname;
string serverUri = path;
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
request.Method = WebRequestMethods.Ftp.Rename;
request.Proxy = null;
request.Credentials = new NetworkCredential(FtpUser, FtpPass);
// change the name of the old folder the old folder
request.RenameTo = DateTime.Now.ToString("yyyyMMddHHmmss");
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
using (var resp = (FtpWebResponse)request.GetResponse())
{
if (resp.StatusCode == FtpStatusCode.FileActionOK)
{
return true;
}
else
{
return false;
}
}
}
catch
{
return false;
}
}
}
Create an instance of that class:
static void Main(string[] args)
{
MyFtpClientftp = new MyFtpClient(ftpuser, ftppass, ftpServerUrl, #"C:\Users\xxxxxxxxxxx");
ftp.UploadDirectory();
Console.WriteLine("DONE");
Console.ReadLine();
}
Unless you're doing this for fun or self-improvement, use a commercial module. I can recommend one from Chilkat, but I'm sure there are others.
Note: I'm pretty sure this does answer the stated problem, What I'm trying to do is to upload a website using FTP in C# (C Sharp).

File.Move throws error when used with BackgroundWorkerr in C#

Solved
I figured out that the GetNewFolderNameBasedOnDate method internally didn't close the file. I have that method fixed and it working normal now
I am trying to move selected files from one folder to another using BackgroundWorker process in C#. Here is my DoWork() method that determine whether to move the files or just copy. My File.Move() throws an exception that "The process cannot access the file because it is being used by another process". I tried different methods as mentioned in the threads here in stackoverflow.
private void FileProcessor_DoWork(object sender, DoWorkEventArgs e)
{
// Copy files
long bytes = 0;
string destSubFolder = String.Empty;
string destFile = string.Empty;
foreach (FileInfo file in oSettings.SourceFiles)
{
try
{
this.BeginInvoke(OnChange, new object[] { new UIProgress(file.Name, bytes, oSettings.MaxBytes) });
destSubFolder = GetNewFolderNameBasedOnDate(file);
//Create a new subfolder under the current active folder
string newPath = Path.Combine(oSettings.TargetFolder, destSubFolder);
// Create a new target folder, if necessary.
if (!System.IO.Directory.Exists(newPath))
{
System.IO.Directory.CreateDirectory(newPath);
}
destFile = Path.Combine(oSettings.TargetFolder, destSubFolder, file.Name);
if (chkDeleteSourceFiles.Checked)
{
FileInfo f = new FileInfo(file.FullName);
if (f.Exists)
{
File.Move(file.FullName, destFile);
}
}
else
{
File.Copy(file.FullName, destFile, true);
}
//Thread.Sleep(2000);
}
catch (Exception ex)
{
UIError err = new UIError(ex, file.FullName);
this.Invoke(OnError, new object[] { err });
if (err.result == DialogResult.Cancel) break;
}
bytes += file.Length;
}
}
I tried to delete the files in "RunWorkerCompleted" method too. But didn't resolve the problem. This fails when it tries to delete the last file in the list.
private void FileProcessor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Operation completed, update UI
ChangeUI(false);
foreach (FileInfo file in oSettings.SourceFiles)
{
File.Delete(file.FullName);
}
}
GetNewFolderNameBasedOnDate() calls GetDateTaken() which was the culprit. Earlier I didn't use FileStream object but used Image myImage = Image.FromFile(filename); I didn't know that Image.FromFile locks the file.
private DateTime GetDateTaken(string fileName)
{
try
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
Image myImage = Image.FromStream(fs);
PropertyItem propItem = myImage.GetPropertyItem(36867);
DateTime dtaken;
//Convert date taken metadata to a DateTime object
string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();
string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));
string firsthalf = sdate.Substring(0, 10);
firsthalf = firsthalf.Replace(":", "-");
sdate = firsthalf + secondhalf;
dtaken = DateTime.Parse(sdate);
return dtaken;
}
}
catch (Exception ex)
{
return DateTime.Now;
}
}
Instead of creating new FileInfo objects, keep it simple and re-use the same one. I suspect the problem is that you have multiple references to the same file in your code, which prevents it from being removed. Try something like this to move it:
if (chkDeleteSourceFiles.Checked)
{
if (file.Exists)
{
file.MoveTo(destFile);
}
}
My guess is that it is the BeginInvoke call to OnChange and the new UIProgress() object that is holding onto the file. Does UIProgress open the file? You could try just using Invoke() and see if that helps.

webservice CopyIntoItems is not working to upload file to sharepoint

The following piece of C# is always failing with
1
Unknown
Object reference not set to an instance of an object
Anybody some idea what i am missing?
try
{
//Copy WebService Settings
String strUserName = "abc";
String strPassword = "abc";
String strDomain = "SVR03";
String FileName = "Filename.xls";
WebReference.Copy copyService = new WebReference.Copy();
copyService.Url = "http://192.168.11.253/_vti_bin/copy.asmx";
copyService.Credentials = new NetworkCredential
(strUserName,
strPassword,
strDomain);
// Filestream of attachment
FileStream MyFile = new FileStream(#"C:\temp\28200.xls", FileMode.Open, FileAccess.Read);
// Read the attachment in to a variable
byte[] Contents = new byte[MyFile.Length];
MyFile.Read(Contents, 0, (int)MyFile.Length);
MyFile.Close();
//Change file name if not exist then create new one
String[] destinationUrl = { "http://192.168.11.253/Shared Documents/28200.xls" };
// Setup some SharePoint metadata fields
WebReference.FieldInformation fieldInfo = new WebReference.FieldInformation();
WebReference.FieldInformation[] ListFields = { fieldInfo };
//Copy the document from Local to SharePoint
WebReference.CopyResult[] result;
uint NewListId = copyService.CopyIntoItems
(FileName,
destinationUrl,
ListFields, Contents, out result);
if (result.Length < 1)
Console.WriteLine("Unable to create a document library item");
else
{
Console.WriteLine( result.Length );
Console.WriteLine( result[0].ErrorCode );
Console.WriteLine( result[0].ErrorMessage );
Console.WriteLine( result[0].DestinationUrl);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
If you will use instead the IP address (http://192.168.11.253) the server name (http://...) this web service works well.
Without understanding more about your specific error, I too would be grasping at straws. It looks like your destinationUrl is an incomplete path. You typically need to specify the entire URL to a site or site collection. So, I would expect your destinationUrl to be something like http://192.168.11.253/[SiteName]/Shared Documents/28200.xls instead of http://192.168.11.253/Shared Documents/28200.xls".

Categories

Resources