Retain Modified Date During SharePoint (online) File Transfers Using ClientContext - c#

I'm essentially trying to download from SharePoint if it has a newer copy of a file or else push mine if mine is newer. I'm never concerned with merging changes in this application. Newer is simply better as the data is all a raw query from a server. So that said, here is what I am doing to compare which file is newer and upload or download accordingly. The problem is, every upload and every download will make the "modified date" be equal to the exact time I do the transfer. I've found I can get the modified date from SharePoint and overwrite the Windows timestamp, but I'm not sure how to go the other way. I'd also accept if there was a way to retain the value to begin with depending on the impact to my current code. So how can I either retain or modify it?
using (var ctx = new ClientContext(DataSharepointSite))
{
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials = GetSharepointCredentials();
var file = ctx.Web.GetFileByServerRelativeUrl(sharepointFile);
var fileData = file.OpenBinaryStream();
ctx.Load(file);
ctx.ExecuteQuery();
using (var sr = new StreamReader(fileData.Value))
{
DateTime lastDataUpdate = System.IO.File.GetLastWriteTime(localFile).ToUniversalTime();
DateTime ShareDate = file.TimeLastModified.ToUniversalTime();
// If SharePoint has a newer file, download it
if (ShareDate > lastDataUpdate)
using (FileStream fs = new FileStream(localFile, FileMode.Create))
{
sr.BaseStream.CopyTo(fs);
}
// Forced to overwrite modified date to match SharePoint
System.IO.File.SetLastWriteTime(localFile, ShareDate);
}
// else if local copy is newer, push to SharePoint
else if (ShareDate < lastDataUpdate)
{
using (FileStream fs = new FileStream(localFile, FileMode.Open))
{
// This, too, is getting a new "modified date" so next compare will re-download
Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, sharepointFile, fs, true);
}
}
}

file.ListItemAllFields["Modified"] = System.IO.File.GetLastWriteTime(localFile);
file.ListItemAllFields.Update();
ctx.ExecuteQuery();

Related

How to add a line to #"https:\\something_like_this.com\Data\text.txt" [duplicate]

This question already has an answer here:
Editing a file on a Sharepoint Server with C#
(1 answer)
Closed 2 years ago.
I'd like to add a line of text to a text file on a SharePoint folder.
Here's what I tried (Please assume that text.txt already exists):
using System.IO;
namespace WriteText
{
class Program
{
static void Main(string[] args)
{
string path = #"https:\\something_like_this.com\Data\text.txt";
//string path = #"C:\Data\text.txt";
File.AppendAllLines( path, new[]{"Hello"});
}
}
}
... However, I got System.NotSupportedException.
When I copy https:\\something_like_this.com\Data\text.txt and paste to a browser,
I can see the file content. It means that the URL is correct.
Why can't I add a line to the text file?
Incidentally, if the path is #"C:\Data\text.txt", it succeeds to add a line.
This is so simple, but how can I fix this?
Could anyone try my code to add a line to a text file on a https:\\your_own_server.com\...?
Thank you in advance.
You will need to programmatically log in to SharePoint through the API, then download the file, then make your change to the file, then upload it back to SharePoint.
Assuming you are using Visual Studio, you will first want to install the nuget package appropriate for your version of SharePoint (2013, 2016, 2019, Online/O365).
Then try something like this:
using (var clientContext = new ClientContext(url))
{
var list = clientContext.Web.Lists.GetByTitle(listTitle);
var listItem = list.GetItemById(listItemId);
clientContext.Load(list);
clientContext.Load(listItem, i => i.File);
clientContext.ExecuteQuery();
var fileRef = listItem.File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
var fileName = Path.Combine(filePath, (string)listItem.File.Name);
using (var fileStream = System.IO.File.Create())
{
fileInfo.Stream.CopyTo(fileStream);
}
File.AppendAllLines(fileName, new[]{"Hello"}); }
using (var fs = new FileStream(fileName, FileMode.Open))
{
Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, fileRef, fs, true);
}
}
Note that if your library requires checkout, you may also need to programmatically check-out the file before uploading your changed file, then checking it back in.

Efficient way to download content of multiple git items via VSTS REST Client Side API

I have a collection of 400 items that I can download from the repository using the VSTS REST Client Side API.
However I don't understand why i have to make 2nd call to get the content of the item? What is the reason behind this?
Is there a way for my code to be efficient when downloading the content?
Here is the below code:
.. code here to set up the connection etc..
//get the items
var gitItems = gitClient.GetItemsAsync(repo.Id, scopePath: "/DemoWebApp/Source/DemoTests/",
download: false, includeContentMetadata: true, includeLinks: true, recursionLevel: VersionControlRecursionType.Full).Result.Where(x => x.IsFolder == false);
foreach(var gitItem in gitItems)
{
var gitItemUrl = gitItem.Url.Split('?')[0];
var fileName = Path.GetFileName(gitItemUrl);
var fileInfo = new FileInfo(gitItem.Path);
var directoryInfo = fileInfo.Directory;
var subDirectory = directoryInfo.Name;
//get the item's content which is a Stream
var itemContent = gitClient.GetItemContentAsync(repo.Id.ToString(), gitItem.Path).Result;
//working directory where to store the files.
var workingDirectory = string.Format("C:\\Download\\{0}", subDirectory);
//only create the directory if it doesnt exist
if (!Directory.Exists(workingDirectory))
{
Directory.CreateDirectory(workingDirectory);
}
//Actually process the files and generate the output
using (FileStream fs = new FileStream(string.Format(workingDirectory + "\\{0}",fileName), FileMode.Create, FileAccess.Write))
{
itemContent.CopyTo(fileStream);
itemContent.Close();
}
}
GetItemsAsync() methed cannot get content of the items and it does not have "includeContent" parameter either.
If you want to download the items, use GetItemZipAsync() method. It will download all the items under the path you specified as a zip on your machine.
Stream res = ghc.GetItemZipAsync("RepoId", "Path").Result;
using (FileStream fs = new FileStream(string.Format(#"D:\a\1.zip"), FileMode.Create, FileAccess.Write))
{
res.CopyTo(fs);
res.Close();
}
According to the docs -> https://learn.microsoft.com/en-us/rest/api/vsts/git/items/get?view=vsts-rest-4.1
URI Parameters
includeContent
boolean
Set to true to include item content when requesting json. Default is false.

Add multiple contacts to SMS Compose Task from isolated storage file

I am trying to make an SMS Compose Task from which I can send group messages. The user adds phone numbers to an isolated storage file and I intend to take the numbers from there.
How do I take the phone numbers from there?
Also how to delete numbers from the isolated storage file?
Here is my isolated storage file code:
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
string fileName = "SOS Contacts.txt";
using (var isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
// we need to check to see if the file exists
if (!isoStorage.FileExists(fileName))
{
// file doesn't exist...time to create it.
isoStorage.CreateFile(fileName);
}
// since we are appending to the file, we must use FileMode.Append
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Append, isoStorage))
{
// opens the file and writes to it.
using (var fileStream = new StreamWriter(isoStream)
{
fileStream.WriteLine(PhoneTextBox.Text);
}
}
// you cannot read from a stream that you opened in FileMode.Append. Therefore, we need
// to close the IsolatedStorageFileStream then open it again in a different FileMode. Since we
// we are simply reading the file, we use FileMode.Open
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Open, isoStorage))
{
// opens the file and reads it.
using (var fileStream = new StreamReader(isoStream))
{
ResultTextBox.Text = fileStream.ReadToEnd();
}
}
}
}
Did you try using the Application Settings using Isolated Storage to store and retrieve data. As you're saving into the Settings, you'll be able to retrieve it anywhere from your application.
Perfect sample would be this.
The following sample is from msdn:
http://code.msdn.microsoft.com/windowsapps/Using-Isolated-Storage-fd7a4233
Hope it helps!

SharpZipLib : Compressing a single file to a single compressed file

I am currently working with SharpZipLib under .NET 2.0 and via this I need to compress a single file to a single compressed archive. In order to do this I am currently using the following:
string tempFilePath = #"C:\Users\Username\AppData\Local\Temp\tmp9AE0.tmp.xml";
string archiveFilePath = #"C:\Archive\Archive_[UTC TIMESTAMP].zip";
FileInfo inFileInfo = new FileInfo(tempFilePath);
ICSharpCode.SharpZipLib.Zip.FastZip fZip = new ICSharpCode.SharpZipLib.Zip.FastZip();
fZip.CreateZip(archiveFilePath, inFileInfo.Directory.FullName, false, inFileInfo.Name);
This works exactly (ish) as it should, however while testing I have encountered a minor gotcha. Lets say that my temp directory (i.e. the directory that contains the uncompressed input file) contains the following files:
tmp9AE0.tmp.xml //The input file I want to compress
xxx_tmp9AE0.tmp.xml // Some other file
yyy_tmp9AE0.tmp.xml // Some other file
wibble.dat // Some other file
When I run the compression all the .xml files are included in the compressed archive. The reason for this is because of the final fileFilter parameter passed to the CreateZip method. Under the hood SharpZipLib is performing a pattern match and this also picks up the files prefixed with xxx_ and yyy_. I assume it would also pick up anything postfixed as well.
So the question is, how can I compress a single file with SharpZipLib? Then again maybe the question is how can I format that fileFilter so that the match can only ever pick up the file I want to compress and nothing else.
As an aside, is there any reason as to why System.IO.Compression not include a ZipStream class? (It only supports GZipStream)
EDIT : Solution (Derived from accepted answer from Hans Passant)
This is the compression method I implemented:
private static void CompressFile(string inputPath, string outputPath)
{
FileInfo outFileInfo = new FileInfo(outputPath);
FileInfo inFileInfo = new FileInfo(inputPath);
// Create the output directory if it does not exist
if (!Directory.Exists(outFileInfo.Directory.FullName))
{
Directory.CreateDirectory(outFileInfo.Directory.FullName);
}
// Compress
using (FileStream fsOut = File.Create(outputPath))
{
using (ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipStream = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(fsOut))
{
zipStream.SetLevel(3);
ICSharpCode.SharpZipLib.Zip.ZipEntry newEntry = new ICSharpCode.SharpZipLib.Zip.ZipEntry(inFileInfo.Name);
newEntry.DateTime = DateTime.UtcNow;
zipStream.PutNextEntry(newEntry);
byte[] buffer = new byte[4096];
using (FileStream streamReader = File.OpenRead(inputPath))
{
ICSharpCode.SharpZipLib.Core.StreamUtils.Copy(streamReader, zipStream, buffer);
}
zipStream.CloseEntry();
zipStream.IsStreamOwner = true;
zipStream.Close();
}
}
}
This is an XY problem, just don't use FastZip. Follow the first example on this web page to avoid accidents.

How to get a file and move it out of the isolated storage?

I want to take a file that stored already in the isolated storage, and copy it out, somewhere on the disk.
IsolatedStorageFile.CopyFile("storedFile.txt","c:\temp")
That doesn't work. Throws IsolatedStorageException and says "Operation not permitted"
I don't see anything in the docs, other than this, which just says that "Some operations aren't permitted", but doesn't say what, exactly. My guess is that it doesn't want you copying out of isolated storage to arbitrary locations on disk. The docs do state that the destination can't be a directory, but even if you fix that, you still get the same error.
As a workaround, you can open the file, read its contents, and write them to another file like so.
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForAssembly())
{
//write sample file
using (Stream fs = new IsolatedStorageFileStream("test.txt", FileMode.Create, store))
{
StreamWriter w = new StreamWriter(fs);
w.WriteLine("test");
w.Flush();
}
//the following line will crash...
//store.CopyFile("test.txt", #"c:\test2.txt");
//open the file backup, read its contents, write them back out to
//your new file.
using (IsolatedStorageFileStream ifs = store.OpenFile("test.txt", FileMode.Open))
{
StreamReader reader = new StreamReader(ifs);
string contents = reader.ReadToEnd();
using (StreamWriter sw = new StreamWriter("nonisostorage.txt"))
{
sw.Write(contents);
}
}
}

Categories

Resources