I'm trying to protect a range in a google sheet using the sheets API (v4) in a .NET project.
I've been able to create a sheet and move it to the desired folder using the Drive API, but now I need to protect a certain range. I'm unsure how to form the request. I'm thinking I may need to use the batchUpdateRequest - but not entirely sure.
I have this so far:
var credential = GoogleCredential.FromFile(PathToServiceAccountKeyFile).CreateScoped(Google.Apis.Sheets.v4.SheetsService.ScopeConstants.Spreadsheets);
var service = new Google.Apis.Sheets.v4.SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
var body = new Google.Apis.Sheets.v4.Data.Request();
body.AddProtectedRange.ProtectedRange.ProtectedRangeId(){
};
var request = service.Spreadsheets.BatchUpdate(body, fileId);
Any help would be greatly appreciated. Thanks!
You can use this code to protect a range:
var spreadsheetId = "spreadsheet id"; //can get from sheet url
var sheetId = "sheet id";
var range = "A1:B10";
var request = new BatchUpdateSpreadsheetRequest()
{
Requests = new List<Request>
{
new()
{
AddProtectedRange = new AddProtectedRangeRequest
{
ProtectedRange = new ProtectedRange
{
Range = new GridRange
{
SheetId = sheetId,
StartRowIndex = 0,
EndRowIndex = 9,
StartColumnIndex = 0,
EndColumnIndex = 1
},
Description = "Protected Range",
WarningOnly = false
}
}
}
}
};
service.Spreadsheets.BatchUpdate(request, spreadsheetId).Execute();
AddProtectedRangeRequest docs
I have to copy existing sheet and rename it. And I cannot find any info how to rename the sheet via Google sheets API v4.
For now I have:
var defaultSheet = service.Spreadsheets
.Get(spreadsheetKey)
.Execute().Sheets
.First(x => x.Properties.Title.Equals("Default sheet"));
var newSheet = Service.Spreadsheets.Sheets.CopyTo(
new CopySheetToAnotherSpreadsheetRequest { DestinationSpreadsheetId = spreadsheetKey },
spreadsheetKey,
(int)defaultSheet.Properties.SheetId);
I hope anyone has any idea how to do it.
Thanks in advance!
Solution (how to copy sheet with specified name):
var defSheet = Service.Spreadsheets.Get(baseUrl).Execute().Sheets.First(x => x.Properties.Title.Equals("OldSheet"));
var newSheet = new Request
{
DuplicateSheet = new DuplicateSheetRequest
{
SourceSheetId = defSheet.Properties.SheetId,
NewSheetName = "NewSheet",
InsertSheetIndex = 1
}
};
var y = new BatchUpdateSpreadsheetRequest { Requests = new List<Request> { newSheet } };
Service.Spreadsheets.BatchUpdate(y, baseUrl).Execute();
I am very new to MS-CRM and I want to retreive all the details of the contact
var executeQuickFindRequest = new OrganizationRequest("ExecuteQuickFind");
executeQuickFindRequest.Parameters = new ParameterCollection();
var entities = new List<string> { "contact", "lead", "account" }; //specify search term
executeQuickFindRequest.Parameters.Add("SearchText", "maria");
//will cause serialisation exception if we don't convert to array
executeQuickFindRequest.Parameters.Add("EntityNames", entities.ToArray());
var executeQuickFindResponse = _orgService.Execute(executeQuickFindRequest);
var result = executeQuickFindResponse.Results;
The data here displayed contains display name's such as address_1_City,email_user
However I want to get there actual names like Address,Email etc etc.
Thanks
Just to extend what BlueSam has mentioned above.
EntityMetadata entityMetaData = retrieveEntityResponse.EntityMetadata;
for (int count = 0; count < entityMetaData.Attributes.ToList().Count; count++)
{
if (entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels.Count > 0)
{
string displayName = entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels[0].Label;
string logicalName = entityMetaData.Attributes.ToList()[count].LogicalName;
AttributeTypeCode dataType = (AttributeTypeCode)entityMetaData.Attributes.ToList()[count].AttributeType;
}
}
Above code will help you to get the display name, logical name and data type for each attribute in the entity. Similarly you can get other information as well from the entityMetaData object as per above code snippet.
As far as I know, you will need to pair it up with the attributes of the entities that are for that request. Here's a sample of how to retrieve an entity:
RetrieveEntityRequest retrieveBankAccountEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = entityName
};
RetrieveEntityResponse retrieveEntityResponse = (RetrieveEntityResponse)_serviceProxy.Execute(retrieveBankAccountEntityRequest);
You can do it easy as below
using (var service = new OrganizationService(CrmConnection.Parse("CRMConnectionString")))
{
var Res = service.Retrieve("sv_answer", new Guid("GUID Of Record"), new ColumnSet("ColumnName "));
}
I have a IEnumerable<object> dataSource which contains a collection anonymous types. The actual structure of the anonymous type won't be known at design time, so I'm trying to find a generic solution that can handle any anonymous type.
How can I load them into epplus to create a spreadsheet? I have a worksheet called ws and I tried:
ws.Cells["A1"].LoadFromCollection(dataSource, true);
However when that runs it outputs all of the anonymous type's properties into a single cell:
{ Id = 10000, Title = This is a test }
I've tried passing in MemberInfo using:
var members = dataSource.First().GetType().GetMembers();
ws.Cells["A1"].LoadFromCollection(this._dataSource, true,
TableStyles.Medium1, BindingFlags.Public, members);
But that throws an exception:
Supplied properties in parameter Properties must be of the same type as T
Any suggestions on how I can create a spreadsheet using anonymous types in c#?
I have tested
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromCollection(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
with this sample data:
var dataSource = Enumerable.Range(1, 100).Select(i => new{ ID=i, Title="Title " + i });
It works fine. It creates two columns with the correct headers and 100 rows.
But you should use anonymous types only if you know the structure at compile time.
You could use a DataTable and LoadFromDataTable instead. Since i don't know how you create the anonymous type i show you just a small sample:
DataTable dataSource = new DataTable();
dataSource.Columns.Add("Id"); // default type is string
dataSource.Columns.Add("Title");
// add other columns
dataSource.Rows.Add("1", "Title1");
// add other rows
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromDataTable(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
You could group the anonymous types to make it easier for exporting with dataTables. The bug "Supplied properties in parameter Properties must be of the same type as T" is still there and a workaround is using DataTables.
// Imagine list is your main datasource
IEnumerable<object> list = Enumerable.Empty<object>(); // Data Source of <object>
// Added anon types at runtime added to the object list
var anonTypesOne = new object[]
{
new { GuidID = Guid.NewGuid(), StringProperty = "the string property" },
new { IntegerID = 1, IntegerProperty = 99 }
};
var anonTypesTwo = new object[]
{
new { StringID = "1", BooleanProperty = true, NumberProperty = 3, StringProperty = "Four" },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 }
};
list = list.Concat(anonTypesOne).Concat(anonTypesTwo);
// Grouping works on anon types so we can group the export into their own tables
var groupings = list.GroupBy(i => i.GetType());
using(var package = new ExcelPackage(new FileInfo("C:\\Temp\\Anon.xlsx")))
{
var ws = package.Workbook.Worksheets.Add("Anonymous Types");
// add each "anon type matched grouping"
foreach(var grouping in groupings)
{
var isNew = ws.Dimension == null; // the sheet is empty if Dimension is null.
var row = 0;
if(isNew)
{
row = 1; // start from the first row
}
else
{
// otherwise there are tables already, start from the bottom
row = ws.Dimension.End.Row;
}
// because of EPP inheritance bug of T, we can just use dataTable
DataTable dt = new DataTable(grouping.Key.Name);
var properties = grouping.Key.GetProperties(); // Get anon type Properties
foreach(var property in properties)
{
dt.Columns.Add(property.Name);
}
foreach(var item in grouping.ToList())
{
var dataRow = dt.NewRow();
foreach(var p in properties) // populate a single row
{
dataRow[p.Name] = p.GetValue(item); // item is anon object instance
}
dt.Rows.Add(dataRow);
}
if(isNew) // load into the top most left cell of the worksheet
ws.Cells[1, 1].LoadFromDataTable(dt, PrintHeaders: true);
else // load from the dimension of current items + 1 row for spacing
ws.Cells[ws.Dimension.End.Row + 1, 1].LoadFromDataTable(dt, PrintHeaders: true);
ws.InsertRow(ws.Dimension.End.Row + 2, 5); // Insert some padding between each group
}
package.Save();
}
I was, this thread is older, but I'm looking for the same problem.
With the following code (VB) I have success.
Carsten
Dim targetFile = New IO.FileInfo(sFN)
Dim dataSource = Enumerable.Range(0, 1).Select(Function(i) New With {.ID = 1000, .Titel = "This is a test "}).ToList
Using epp = New OfficeOpenXml.ExcelPackage(targetFile)
Dim ws = epp.Workbook.Worksheets.Add("lst_Anonymous")
ws.Cells(1, 1).LoadFromCollection(dataSource, True,
OfficeOpenXml.Table.TableStyles.Medium1,
Reflection.BindingFlags.Public,
dataSource.GetType.GetGenericArguments()(0).GetProperties)
epp.Save()
End Using
I am working on generating an excel template from code. When I run the piece to create my WorkBook, I get no errors in code, however when I go to open the Excel document, I get an error indicating that the file is unreadable. I am able to click to open it anyway, and I get the following message
Removed Records: Worksheet properties from /xl/workbook.xml part (Workbook)
Any idea what might be wrong in my code please?
public void CreatePackage()
{
using (SpreadsheetDocument package = SpreadsheetDocument.Create(FilePath, SpreadsheetDocumentType.Workbook))
{
CreateParts(package);
}
}
private void CreateParts(SpreadsheetDocument document)
{
ExcelWorkBook excelworkbook = new ExcelWorkBook();
ExcelSheetHelper excelworksheet = new ExcelSheetHelper();
ExcelSharedStringsTable excelsharedtable = new ExcelSharedStringsTable();
ExcelWorkSheetPartBuilder excelworksheetbuilder = new ExcelWorkSheetPartBuilder();
ExtendedFilePropertiesPart extendedFilePropertiesPart1 = document.AddNewPart<ExtendedFilePropertiesPart>("rId3");
ExcelWorkSheetPartBuilder.GenerateExtendedFilePropertiesPart1Content(extendedFilePropertiesPart1);
WorkbookPart workbookPart1 = document.AddWorkbookPart();
excelworkbook.GenerateWorkbookPartContent(workbookPart1);
WorkbookStylesPart workbookStylesPart1 = workbookPart1.AddNewPart<WorkbookStylesPart>("rId5");
ExcelWorkBook.GenerateWorkbookStylesPart1Content(workbookStylesPart1);
SetPackageProperties(document);
}
public void GenerateWorkbookPartContent(WorkbookPart workbookPart1)
{
Workbook workbook = new Workbook();
workbook.AddNamespaceDeclaration("r", rNameSpace);
FileVersion fileVersion1 = GenerateFileVersion();
WorkbookProperties workbookProperties1 = GenerateWorkbookProperties();
BookViews bookViews1 = GenerateBookViews();
Sheets sheets1 = GenerateSheets();
DefinedNames definedNames1 = GenerateDefinedNames();
CalculationProperties calculationProperties1 = GenerateCalculationProperties();
CustomWorkbookViews customWorkbookViews1 = GenerateCustomWorkbookViews();
workbook.Append(fileVersion1);
workbook.Append(workbookProperties1);
workbook.Append(bookViews1);
workbook.Append(sheets1);
workbook.Append(definedNames1);
workbook.Append(calculationProperties1);
workbook.Append(customWorkbookViews1);
workbookPart1.Workbook = workbook;
}
// Creates an FileVersion instance and adds its children.
public FileVersion GenerateFileVersion()
{
FileVersion fileVersion1 = new FileVersion() { ApplicationName = "xl", LastEdited = "5", LowestEdited = "5", BuildVersion = "9303" };
return fileVersion1;
}
// Creates an WorkbookProperties instance and adds its children.
public WorkbookProperties GenerateWorkbookProperties()
{
WorkbookProperties workbookProperties1 = new WorkbookProperties() { HidePivotFieldList = true };
return workbookProperties1;
}
// Creates an BookViews instance and adds its children.
public BookViews GenerateBookViews()
{
BookViews bookViews1 = new BookViews();
WorkbookView workbookView1 = new WorkbookView() { XWindow = -75, YWindow = 270, WindowWidth = (UInt32Value)15435U, WindowHeight = (UInt32Value)6930U };
bookViews1.Append(workbookView1);
return bookViews1;
}
// Creates an Sheets instance and adds its children.
public Sheets GenerateSheets()
{
Sheets sheets1 = new Sheets();
Sheet sheet1 = new Sheet() { Name = String.Format("{0}", worksheetname), SheetId = (UInt32Value)8U, Id = "rId1" };
sheets1.Append(sheet1);
return sheets1;
}
// Creates an DefinedNames instance and adds its children.
public DefinedNames GenerateDefinedNames()
{
DefinedNames definedNames1 = new DefinedNames();
DefinedName definedName1 = new DefinedName() { Name = "_xlnm._FilterDatabase", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName1.Text = String.Format("\'{0}\'!$A$6:$EO$1269", worksheetname);
DefinedName definedName2 = new DefinedName() { Name = "Z_32BE30F1_B609_44A0_A38A_666CEFFB64E2_.wvu.Cols", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName2.Text = String.Format("\'{0}\'!#REF!", worksheetname);
DefinedName definedName3 = new DefinedName() { Name = "Z_32BE30F1_B609_44A0_A38A_666CEFFB64E2_.wvu.FilterData", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName3.Text = String.Format("\'{0}\'!#REF!", worksheetname);
DefinedName definedName4 = new DefinedName() { Name = "Z_5098B70B_692A_450A_8DAE_5172C296966E_.wvu.FilterData", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName4.Text = String.Format("\'{0}\'!#REF!", worksheetname);
DefinedName definedName5 = new DefinedName() { Name = "Z_7C00A233_927A_41FE_802C_48F5F9E9D5B6_.wvu.FilterData", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName5.Text = String.Format("\'{0}\'!#REF!",worksheetname);
DefinedName definedName6 = new DefinedName() { Name = "Z_AC112ED6_0017_40BF_884A_9B7959C37BF0_.wvu.FilterData", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName6.Text = String.Format("\'{0}\'!#REF!", worksheetname);
DefinedName definedName7 = new DefinedName() { Name = "Z_E444BF53_6DCE_4910_823C_F60AE88C96EE_.wvu.FilterData", LocalSheetId = (UInt32Value)0U, Hidden = true };
definedName7.Text = String.Format("\'{0}\'!#REF!",worksheetname);
definedNames1.Append(definedName1);
definedNames1.Append(definedName2);
definedNames1.Append(definedName3);
definedNames1.Append(definedName4);
definedNames1.Append(definedName5);
definedNames1.Append(definedName6);
definedNames1.Append(definedName7);
return definedNames1;
}
// Creates an CalculationProperties instance and adds its children.
public CalculationProperties GenerateCalculationProperties()
{
CalculationProperties calculationProperties1 = new CalculationProperties() { CalculationId = (UInt32Value)125725U };
return calculationProperties1;
}
// Creates an CustomWorkbookViews instance and adds its children.
public CustomWorkbookViews GenerateCustomWorkbookViews()
{
CustomWorkbookViews customWorkbookViews1 = new CustomWorkbookViews();
CustomWorkbookView customWorkbookView1 = new CustomWorkbookView() { Name = "A - Personal View", Guid = "{5098B70B-692A-450A-8DAE-5172C296966E}", MergeInterval = (UInt32Value)0U, PersonalView = true, Maximized = true, XWindow = 1, YWindow = 1, WindowWidth = (UInt32Value)1366U, WindowHeight = (UInt32Value)494U, ActiveSheetId = (UInt32Value)3U };
CustomWorkbookView customWorkbookView2 = new CustomWorkbookView() { Name = "B - Personal View", Guid = "{7C00A233-927A-41FE-802C-48F5F9E9D5B6}", MergeInterval = (UInt32Value)0U, PersonalView = true, Maximized = true, XWindow = 1, YWindow = 1, WindowWidth = (UInt32Value)1024U, WindowHeight = (UInt32Value)487U, ActiveSheetId = (UInt32Value)3U };
CustomWorkbookView customWorkbookView3 = new CustomWorkbookView() { Name = "C - Personal View", Guid = "{32BE30F1-B609-44A0-A38A-666CEFFB64E2}", MergeInterval = (UInt32Value)0U, PersonalView = true, Maximized = true, XWindow = 1, YWindow = 1, WindowWidth = (UInt32Value)1280U, WindowHeight = (UInt32Value)481U, ActiveSheetId = (UInt32Value)3U };
customWorkbookViews1.Append(customWorkbookView1);
customWorkbookViews1.Append(customWorkbookView2);
customWorkbookViews1.Append(customWorkbookView3);
return customWorkbookViews1;
}
public void ValidateDocument()
{
try
{
OpenXmlValidator validator = new OpenXmlValidator();
int count = 0;
IDictionary<String, String> ErrorLog = new Dictionary<String, String>();
using (StreamWriter f = new StreamWriter("Errolog.txt"))
{
foreach (ValidationErrorInfo error in validator.Validate(WordprocessingDocument.Open(FilePath, true)))
{
count++;
f.WriteLine("Error " + count);
f.WriteLine("Description: " + error.Description);
f.WriteLine("Path: " + error.Path.XPath);
f.WriteLine("Part: " + error.Part.Uri);
f.WriteLine("-------------------------------------------");
f.WriteLine("-------------------------------------------");
f.WriteLine("-------------------------------------------");
}
f.Flush();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
In my specific case, I was having this problem because of too long Worksheet names. This is what was happening to me:
On the first run of my program, I was trying to creating Worksheets with really big names.
Excel automatically cropped the big names to 31 characters. No exception was thrown. That is, I thought I was saving the original big name but I was actually saving the 31 characters long cropped string.
On the second run of my program, I was checking if this specific Worksheet existed already, but I thought it didn't exist because the existing one was cropped.
I was saving the Worksheet again. No exception thrown, but then, the new one was also cropped and now the XML contains 2 definitions of the same worksheet.
This causes Excel to attempt to repair the resulting Spreadsheet. Even though it works properly, I think it was simply throwing away the second one and using the first, which wasn't what I wanted.
I fixed the problem by cropping the 31 characters beforehand, before all the comparisons. Now it works perfectly
I know this question asked long ago, i thought my experience will solve someones problem. So am posting my answer here.
I had a similar problem. It occurs due the no. of characters in a sheet name exceeds the limit 31. Sheet name characters must be <= 31.
It won't throw any exception while creating, but gives error while opening in Microsoft Excel.
The Open XML SDK does not constrain you to producing a valid document. However, there is the OpenXmlValidator class which you can use to report any errors in the generated document. See this, which has a good example.
I had this error as well, because I was using 0 as my SheetId, something like:
var sheet1 = new Sheet() { Name = "Test", SheetId = (UInt32Value)0U, Id = "rId1" };
Excel starts counting from 1, not 0. This is not only true for row numbers, it applies to sheet numbers as well.
Yes, As Murugesan Said in the above comment, i fixed this error by renaming the file name of my excel document.
For example: In my case , the name of the document was 'My Sample Export Data Sheet'. I have renamed the file to 'MySampleExportDataSheet' and everything worked well later.
In my case the tab name consists single quote, i.e.: "my tab's".
I just omitted them:
title = title.replace(/'/g, "");
In our case, some of our worksheet names contained square brackets, e.g.:
Students [Primary]
Students [Secondary]
Replacing square brackets with round brackets fixed it:
Students (Primary)
Students (Secondary)
(For some reason, our customer didn't want these worksheets called Primary Students, Secondary Students, hence using brackets)
For us, the error message when opening the workbook in Excel was:
We found a problem with some content in 'workbook.xlsx'.
Do you want us to try and recover as much as we can?
If you trust the source of this workbook, click Yes.
Clicking Yes then allowed Excel to open the workbook, and it displayed the message
Repaired Records: Worksheet properties from /xl/workbook.xml part (Workbook)
Just in case someone finds this. It may also be because your sheet names are not unique. My issue was that, because of the char limit, 3 sheets wound up with the exact same name. When I repaired the file Excel renamed the duplicate sheets.
So if the above answers don't work, repair the file then look for a sheet named Recovered_Sheet1. That will tell you what sheet name has the issue (duplicate in my case).