I'm fairly new to coding and c#. I'm building an app that accesses google spreadsheets via an API, I turn this data into XML, zip it and write it to a stream. It works fine, but instead of adding every spreadsheet ID manually to my list I want to make another API call that will retrieve every ID in my google sheets account so that I can store them to a list and update it every time I run the app.
I'm banging my head off a wall looking for answers but I think this is not available via a sheets API but maybe through the drive API??, any help would be greatly appreciated, I'm not looking for anyone to write my code, but please point me in the right direction, or am I trying to do something that cannot be done?
public class GoogleSheetsReader
{
private string apiKey;
public Stream OutStream { get; set; }
List<string> SpreadSheetIdList { get; set; }
public GoogleSheetsReader(string apiKey)
{
this.apiKey = apiKey;
}
public Stream Main()
{
SheetsService sheetsService = new SheetsService(new BaseClientService.Initializer
{
HttpClientInitializer = GetCredential(),
ApplicationName = "My Project To XML",
ApiKey = apiKey,
});
using (MemoryStream memory = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(memory, ZipArchiveMode.Create))
{
SpreadSheetIdList = new List<string>(); // not the best place for the list, just testing funtionality
SpreadSheetIdList.Add("1oZlfj6XZOrPs9Qti9K9iKL6itZChM8dlwwJFSvBNzUc");
SpreadSheetIdList.Add("1oU3sjd7QoOgQ2PvmC7NxciyM1MRXns6-Z9vMayFgOjU");
foreach (var spreadSheetId in SpreadSheetIdList)
{
var ssRequest = sheetsService.Spreadsheets.Get(spreadSheetId);
Data.Spreadsheet service = ssRequest.Execute();
foreach (var sheet in service.Sheets)
{
var sheetName = sheet.Properties.Title;
SpreadsheetsResource.ValuesResource.GetRequest request = sheetsService.Spreadsheets.Values.Get(spreadSheetId, sheetName);
SpreadsheetsResource.GetRequest requestForSpreadSheet = sheetsService.Spreadsheets.Get(spreadSheetId);
requestForSpreadSheet.Ranges = sheetName;
Data.Spreadsheet response1 = requestForSpreadSheet.Execute();
var spreadSheetName = response1.Properties.Title;
Data.ValueRange response = request.Execute();
ZipArchiveEntry entry = zip.CreateEntry($"{spreadSheetName}\\{sheetName}.xml");
using (Stream ZipFile = entry.Open())
{
byte[] data = Encoding.ASCII.GetBytes(SchemaMaker(response)); // SchemaMaker converts my sheet data to required xml format
ZipFile.Write(data, 0, data.Length);
}
}
}
}
OutStream = new MemoryStream(memory.ToArray());
}
return OutStream;
}
public string SchemaMaker(ValueRange _param)
{
var result = "<TABLE>";
var headers = _param.Values[0];
for (int i = 1; i < _param.Values.Count; i++)
{
result = result + "<ROW>";
for (int j = 0; j < _param.Values[i].Count; j++)
{
result = result + $"<{headers[j]}>{_param.Values[i][j]}</{headers[j]}>";
}
result = result + "</ROW>";
}
result = result + "</TABLE>";
var element = XElement.Parse(result);
var settings = new System.Xml.XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
settings.NewLineOnAttributes = true;
var xmlFormat = element.ToString();
return xmlFormat;
}
public static UserCredential GetCredential()
{
string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
return null;
}
}
Related
I am developing an aplication that send and email with one or multiple attachments via Microsoft Graph, but when try to upload file send me an error: ": Invalid total bytes specified in the Content-Range header"
i asume that i must specifi Range Value in same where, but no idea.
This is my code:
private static async void SenMailUsingMicrosoftGraph(List<String>Destinations, List<String>Cc, string HidenCopy, string Body, string Title, List<FileInfo>Filess);
{
ClientSecretCredential credential = new ClientSecretCredential("MyTenantID", "MyClientId", "MyClientSecret");
List<Recipient> recipientsDestinatarios = new List<Recipient>();
List<Recipient> recipientsCopias = new List<Recipient>();
foreach (var c in Destinations)
{
recipientsDestinatarios.Add(
new Recipient
{
EmailAddress = new EmailAddress
{
Address = c
}
});
}
foreach (var mail in Cc)
{
recipientsCopias.Add(
new Recipient
{
EmailAddress = new EmailAddress
{
Address = mail
}
});
}
#endregion
var message = new Microsoft.Graph.Message
{
Subject = Title,
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = Body
},
ToRecipients = recipientsDestinatarios
,
CcRecipients = recipientsCopias
,
BccRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress=new EmailAddress{Address=Hiden}
}
}
};
GraphServiceClient graphClient = new GraphServiceClient(credential);
#endregion
#region adjuntar ficheros
var msgResult = await graphClient.Users["myemail#mycompany.com"].MailFolders.Drafts.Messages
.Request()
.WithMaxRetry(9)
.AddAsync(message);
foreach (var Archivo in Filess)
{
var attachmentContentSize = Archivo.Length;
var attachmentItem = new AttachmentItem
{
AttachmentType = AttachmentType.File,
Name = Archivo.Name,
Size = attachmentContentSize,
};
//initiate the upload session for large files
var uploadSession = await graphClient.Users["myemail#mycompany.com"].Messages[msgResult.Id].Attachments
.CreateUploadSession(attachmentItem)
.Request()
.PostAsync();
var maxChunkSize = 1024 * 320;
var allBytes = System.IO.File.ReadAllBytes(Archivo.FullName);
using (var stream = new MemoryStream(allBytes))
{
stream.Position = 0;
LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, stream, maxChunkSize);
await largeFileUploadTask.UploadAsync();
}
}
await graphClient.Users["myemail#mycompany.com"].Messages[msgResult.Id].Send().Request().PostAsync();
}
I try something like this:
var content = new System.Net.Http.Headers.ContentRangeHeaderValue(0,MyFile.Length-1,MyFile.Length);
but i dont now how to asign this content variable, i think that must go in the uploadSession but dont know how.
------------------------------------EDIT------------------------------
included a Picture where see that the size of the attachment is not zero
I am using the following code to upload video on Vimeo. I want to add filename as video title currently I am getting Untitled video with the above code
please guide me how to add Title/Name
public async Task<IActionResult> UploadVideos([FromForm] IFormFile videoFile)
{
string tagName = "tagName";
//var files = Request.Form.Files;
//IFormFile file = files[0];
string uploadStatus = "";
var getVideo = new Video();
try
{
if (videoFile != null)
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
VimeoClient vimeoClient = new VimeoClient(accessToken);
var authcheck = await vimeoClient.GetAccountInformationAsync();
if (authcheck.Name != null)
{
IUploadRequest uploadRequest = new UploadRequest();
//Stream stream = file.OpenReadStream();
//using(var memoryStream = new MemoryStream())
//{
// stream.CopyTo(memoryStream);
// memoryStream.ToArray();
//}
BinaryContent binaryContent = new BinaryContent(obj.videoFile.OpenReadStream(), obj.videoFile.ContentType);
int chunkSize = 0;
int contentLength = Convert.ToInt32(obj.videoFile.Length);
int temp1 = contentLength / 1024;
binaryContent.OriginalFileName = "Test Name";
if (temp1 > 1)
{
chunkSize = temp1 / 1024;
if (chunkSize == 0)
{
chunkSize = 1048576;
}
else
{
if (chunkSize > 10)
{
chunkSize = chunkSize / 10;
}
chunkSize = chunkSize * 1048576;
}
}
else
{
chunkSize = 1048576;
}
var checkChunk = chunkSize;
var status = "uploading";
uploadRequest = await vimeoClient.UploadEntireFileAsync(binaryContent, chunkSize, null);
var _tag = tagName;
var tagVideo = await vimeoClient.AddVideoTagAsync(uploadRequest.ClipId.GetValueOrDefault(), _tag);
while (status != "available")
{
getVideo = await vimeoClient.GetVideoAsync(long.Parse(uploadRequest.ClipId.Value.ToString()));
status = getVideo.Status;
}
uploadStatus = String.Concat("file Uploaded ", getVideo.Files[0].LinkSecure);
}
}
return Ok(new { status = uploadStatus, video = getVideo });
}
catch (Exception ex)
{
return BadRequest(ex.ToString());
}
}
I tried to set title with this binaryContent.OriginalFileName but its results untitled video. Please guide by providing the modification required in the api
I try to refer to the Vimeo documentation and come to know that you could use the Pull approach or you could set metadata for the video to set the title.
Video uploads on Vimeo include metadata such as the name of the video and the video's privacy settings. Besides being useful as titles and text descriptors, metadata are also a key component in strategies for search engine optimization.
You can specify values for a video's metadata fields in the body of the initial POST request of an upload, like this:
{
"upload": {
"approach": "tus",
"size": 800000000
},
"name": "My Video",
"privacy": { "view": "nobody" }
}
If you don’t specify a name for your video, we automatically give it the name Untitled, unless you upload it with the pull approach. In that case, we use the file name of the video.
For more detailed information, please refer to Setting video metadata point in this document.
My code looks like this
CloudFileClient client = ...;
client.GetShareReference("fileStorageShare")
.GetRootDirectoryReference()
.GetDirectoryReference("one/two/three")
.Create();
This errors if directories one or two don't exist. Is there a way to create these nested directories with a single call?
It is impossible. The SDK does not support it this way, you should create them one by one.
A issue has already submitted here.
If you wanna create them one by one, you can use the following sample code:
static void NestedDirectoriesTest()
{
var cred = new StorageCredentials(accountName, accountKey);
var account = new CloudStorageAccount(cred, true);
var client = account.CreateCloudFileClient();
var share = client.GetShareReference("temp2");
share.CreateIfNotExists();
var cloudFileDirectory = share.GetRootDirectoryReference();
//Specify the nested folder
var nestedFolderStructure = "Folder/SubFolder";
var delimiter = new char[] { '/' };
var nestedFolderArray = nestedFolderStructure.Split(delimiter);
for (var i=0; i<nestedFolderArray.Length; i++)
{
cloudFileDirectory = cloudFileDirectory.GetDirectoryReference(nestedFolderArray[i]);
cloudFileDirectory.CreateIfNotExists();
Console.WriteLine(cloudFileDirectory.Name + " created...");
}
}
Following the advice of Ivan Yang, I adapted my code using Azure.Storage.Files.Shares (Version=12.2.3.0).
Here's my contribution:
readonly string storageConnectionString = "yourConnectionString";
readonly string shareName = "yourShareName";
public string StoreFile(string dirName,string fileName, Stream fileContent)
{
// Get a reference to a share and then create it
ShareClient share = new ShareClient(storageConnectionString, shareName);
share.CreateIfNotExists();
// Get a reference to a directory and create it
string[] arrayPath = dirName.Split('/');
string buildPath = string.Empty;
var tempoShare = share;
ShareDirectoryClient directory = null; // share.GetDirectoryClient(dirName);
// Here's goes the nested directories builder
for (int i=0; i < arrayPath.Length; i++)
{
buildPath += arrayPath[i];
directory = share.GetDirectoryClient(buildPath);
directory.CreateIfNotExists();
buildPath += '/';
}
// Get a reference to a file and upload it
ShareFileClient file = directory.GetFileClient(fileName);
using (Stream stream = fileContent)
{
file.Create(stream.Length);
file.UploadRange(new HttpRange(0, stream.Length), stream);
}
return directory.Path;
}
Here is a simplified version of Hagen's code:
public async Task<ShareFileClient> CreateFileClient(string connection, string shareName, string path)
{
var share = new ShareClient(connection, shareName);
await share.CreateIfNotExistsAsync();
var dir = share.GetRootDirectoryClient();
var pathChain = path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
int dirCount = pathChain.Length - 1;
for (int i = 0; i < dirCount; ++i)
{
dir = dir.GetSubdirectoryClient(pathChain[i]);
await dir.CreateIfNotExistsAsync();
}
return dir.GetFileClient(pathChain[dirCount]);
}
I want to send a photo using the Telegram.Bot library, but it's not working!
Here is my code:
private void btnSendImage_Click(object sender, RoutedEventArgs e)
{
var Bot = new Telegram.Bot.Api(token);
Task<Telegram.Bot.Types.Update[]> res = Bot.GetUpdates();
List<string> users = GetIds();
foreach (var update in res.Result)
{
if (!users.Contains("" + update.Message.Chat.Id))
{
AddId("" + update.Message.Chat.Id);
}
}
users = GetIds();
foreach (var item in users)
{
if (item.Length > 0)
{
var rep = Bot.SendPhoto(Convert.ToInt32(item), txtImagePath.Text, txtMessage.Text);
}
}
}
and txtImagePath.text= "D:\Projects\Telegram Bot\Telegram Bot\bin\Debug\4.jpg";
I tested it with Bot.SendMessage and it worked fine, but I can't send a photo!
I used this code and it's worked!
var FileUrl = #"C:\\Users\\User\\Documents\\20160201_204055.jpg";
using (var stream = System.IO.File.Open(FileUrl, FileMode.Open))
{
FileToSend fts = new FileToSend();
fts.Content = stream;
fts.Filename = FileUrl.Split('\\').Last();
var test = await bot.SendPhoto("#channel Name or chat_id", fts, "My Text");
}
you need to pass a Stream to the function if you want to send an new image.
using (var stream = File.Open(txtImagePath.Text, FileMode.Open))
{
var rep = await Bot.SendPhoto(Convert.ToInt32(item), stream, txtMessage.Text);
}
I am trying validate Google Account using WebClient.
class PostDataBuilder
{
private static Dictionary<string, string>
ToPropertyDictionary(object data)
{
var values = data
.GetType()
.GetProperties()
.Select(x => new {
Key = x.Name,
Value = x.GetValue(data, null)
});
var result = new Dictionary<string, string>();
foreach (var item in values)
result.Add(item.Key, item.Value.ToString());
return result;
}
public static string Build(object data)
{
string result = "";
var dict = ToPropertyDictionary(data);
foreach (var name in dict.Keys)
result += name + "=" + HttpUtility.UrlEncode(dict[name]) + "&";
return result.Substring(0, result.Length - 1);
}
}
class Program
{
static void Main(string[] args)
{
string postText = PostDataBuilder.Build(
new
{
dsh = "-1903339439726094408",
GALX = "-Ggrv6gqusk",
timeStmp = "",
secTok = "",
Email = "WrongEmail#gmail.com",
Passwd = "WrongPassword",
signIn = "?????",
rmShown = "1"
});
byte[] data = Encoding.UTF8.GetBytes(postText);
WebClient wc = new WebClient();
byte[] result = wc.UploadData(
new Uri("https://accounts.google.com/ServiceLoginAuth"),
"POST", data);
string resultText = Encoding.UTF8.GetString(result);
}
}
ResultText variable has setted , even if data is correct. What's wrong?
You shouldn't ever screw around with login services such as the Google one or try to fake a browser. In the end it could be considered attempt hacking or whatever and it's very likely to break the next time they update their page (or even just because your IP changes).
Instead use OpenID or OAuth as described here.