I'm trying to read the colors used in an Excel Chart Template (mychart.crtx). But I can't figure out how to open the file using the Open XML toolkit. It doesn't appear to be possible using SDK Tool.
Can it be done?
This is indeed not possible with the Open XML SDK, because it only provides the WordprocessingDocument (for .docx etc.), SpreadsheetDocument (for .xlsx etc.), and PresentationDocument (for .pptx etc.) classes for opening Word, Excel, and PowerPoint documents and templates.
However, Office documents and your Excel Chart Templates (.crtx) are all based on the Open Packaging Conventions (OPC). You can use the classes provided in the System.IO.Packaging namespace to work with any OPC-based document, including those Excel Chart Templates.
The following picture shows the structure of a sample ChartTemplate.crtx that I created for testing purposes. I used the Open XML Package Editor for Modern Visual Studios to inspect that package.
Using the System.IO.Packaging classes, the Package class represents whole packages (e.g., ChartTemplate.crtx). The PackagePart class represents XML and other files contained in a package. Each PackagePart has a URI (e.g., /chart/chart.xml, /chart/charts/colors1.xml), a content type, and zero or more relationships to other parts.
The following code snippet opens the sample Package, gets the PackagePart, loads the root XML element from the part and makes certain assertions to demonstrate what it got.
[Fact]
public void LoadRootElement_Chart_SuccessfullyLoaded()
{
using Package package = Package.Open("Resources\\ChartTemplate.crtx", FileMode.Open, FileAccess.Read);
PackagePart packagePart = package.GetPart(new Uri("/chart/chart.xml", UriKind.Relative));
XElement rootElement = LoadRootElement(packagePart);
Assert.Equal(C.chartSpace, rootElement.Name);
Assert.NotEmpty(rootElement.Elements(C.chart).Elements(C.title));
Assert.NotEmpty(rootElement.Elements(C.chart).Elements(C.plotArea));
Assert.NotEmpty(rootElement.Elements(C.chart).Elements(C.legend));
}
The LoadRootElement() method is straightforward:
private static XElement LoadRootElement(PackagePart packagePart)
{
using Stream stream = packagePart.GetStream(FileMode.Open, FileAccess.Read);
return XElement.Load(stream);
}
And I've created a helper class C to provide the required XML namespace and names for use with the XElement class, which, like XNamespace and XName, is defined in the System.Xml.Linq namespace.
private static class C
{
public static readonly XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart";
public static readonly XName chart = c + "chart";
public static readonly XName chartSpace = c + "chartSpace";
public static readonly XName lang = c + "lang";
public static readonly XName legend = c + "legend";
public static readonly XName plotArea = c + "plotArea";
public static readonly XName title = c + "title";
public static readonly XName val = "val";
}
As always, the full source code can be found in my CodeSnippets GitHub repository. Look for the ChartTemplateTests class.
Related
I am recording the application through Wiremock using JAVA DSL, Do we have the option to customize the mapping file names? instead of getting the filename which is generated from wiremock..
Example: searchpanel_arrivalairport_th-72f9b8b7-076f-4102-b6a8-aa38710fde1b.json (Generated form wiremock using java )
I am expecting the above file name with my desired naming convention like
seacrpanel_airport_LGW.json
Custom filenames can be added by customizing StubMappingJsonRecorder.
I added CustomStubMappingJsonRecorder and override writeToMappingAndBodyFile method.
if(fileName!=null && !fileName.equals("")){
mappingFileName=fileName+"-mapping.json";
bodyFileName=fileName+"-body.json";
}else {
mappingFileName = UniqueFilenameGenerator.generate(request.getUrl(),
"mapping", filed);
bodyFileName = UniqueFilenameGenerator.generate(request.getUrl(), "body",
fileId, ContentTypes.determineFileExtension(request.getUrl(),
response.getHeaders().getContentTypeHeader(), body));
}
There's no easy way to do this at the moment. It is however possible. As #santhiya-ps says you need to write your own implementation of RequestListener, probably using StubMappingJsonRecorder as a template.
You can't extend it and override writeToMappingAndBodyFile as that method is private, but that is the method you probably want to change.
import com.github.tomakehurst.wiremock.common.*;
import com.github.tomakehurst.wiremock.core.*;
import com.github.tomakehurst.wiremock.http.*;
import java.util.List;
import static com.github.tomakehurst.wiremock.core.WireMockApp.*;
class NameTemplateStubMappingJsonRecorder implements RequestListener {
private final FileSource mappingsFileSource;
private final FileSource filesFileSource;
private final Admin admin;
private final List<CaseInsensitiveKey> headersToMatch;
private final IdGenerator idGenerator = new VeryShortIdGenerator();
public NameTemplateStubMappingJsonRecorder(Admin admin) {
this.mappingsFileSource = admin.getOptions().filesRoot().child(MAPPINGS_ROOT);
this.filesFileSource = admin.getOptions().filesRoot().child(FILES_ROOT);
this.admin = admin;
this.headersToMatch = admin.getOptions().matchingHeaders();
}
#Override
public void requestReceived(Request request, Response response) {
// TODO copy StubMappingJsonRecorder changing as required...
}
}
You can then register your RequestListener as so:
WireMockServer wireMockServer = new WireMockServer();
wireMockServer.addMockServiceRequestListener(
new NameTemplateStubMappingJsonRecorder(wireMockServer)
);
wireMockServer.start();
So long as you still store the mapping files in the expected directory (stored in FileSource mappingsFileSource above, which will be ${rootDir}/mappings, where rootDir is configured as explained in Configuration - File Locations) they should be loaded successfully as all files with extension json in that dir are loaded as mappings.
It would be much easier if StubMappingJsonRecorder took a strategy for generating these names - it might be worth creating an issue on the WireMock repo asking for an easier way to do this. I'd suggest getting an agreement on a basic design before raising a PR though.
Need to create a digital signed excel file and then validate the signature when uploaded in C#.
On its own, the SpreadsheetDocument.AddDigitalSignatureOriginPart() method does not secure an Excel file. The same is true for the corresponding methods of the WordprocessingDocument and PresentationDocument classes. Those methods only add an empty DigitalSignatureOriginPart that serves as the origin of one or more XmlSignaturePart instances, each of which contains a ds:Signature element based on the W3C Recommendation XML Signature Syntax and Processing Version 1.1 (XMLDSIG).
To secure an Excel file, or any file based on the Open Packaging Conventions (OPC), the most straightforward approach is to use the PackageDigitalSignatureManager class, which is contained in the System.IO.Packaging namespace as provided by the WindowsBase.dll assembly. Thus, if you are targeting the full .NET Framework (e.g., net471), you can use it. However, if you are targeting .Net Core, you need to implement that functionality yourself.
The following code example shows how you can use the PackageDigitalSignatureManager class:
using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.Linq;
namespace CodeSnippets.Windows.IO.Packaging
{
public static class DigitalSignatureManager
{
public static void Sign(Package package)
{
var dsm = new PackageDigitalSignatureManager(package)
{
CertificateOption = CertificateEmbeddingOption.InSignaturePart
};
List<Uri> parts = package.GetParts()
.Select(part => part.Uri)
.Concat(new[]
{
// Include the DigitalSignatureOriginPart and corresponding
// relationship part, since those will only be added when
// signing.
dsm.SignatureOrigin,
PackUriHelper.GetRelationshipPartUri(dsm.SignatureOrigin)
})
.ToList();
dsm.Sign(parts);
}
public static VerifyResult VerifySignature(Package package)
{
var dsm = new PackageDigitalSignatureManager(package);
return dsm.VerifySignatures(true);
}
}
}
In case you need to implement that functionality yourself, it helps to make yourself familiar with a number of sources:
The Digital Signing Framework of the Open Packaging Conventions
How to: Sign XML Documents with Digital Signatures
System.Security.Cryptography.Xml Namespace
Based on those sources, I created a partial sample implementation that works with .Net Core. The following snippet shows the void Sign(OpenXmlPackage, X509Certificate2) method that takes an OpenXmlPackage and an X509Certificate2 and creates a valid signature:
public static void Sign(OpenXmlPackage openXmlPackage, X509Certificate2 certificate)
{
if (openXmlPackage == null) throw new ArgumentNullException(nameof(openXmlPackage));
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
RSA privateKey = certificate.GetRSAPrivateKey();
using SHA256 hashAlgorithm = SHA256.Create();
// Create KeyInfo.
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(certificate));
// Create a Signature XmlElement.
var signedXml = new SignedXml { SigningKey = privateKey, KeyInfo = keyInfo };
signedXml.Signature.Id = Constants.PackageSignatureId;
signedXml.SignedInfo.SignatureMethod = Constants.SignatureMethod;
signedXml.AddReference(CreatePackageObjectReference());
signedXml.AddObject(CreatePackageObject(openXmlPackage.Package, hashAlgorithm));
signedXml.ComputeSignature();
XmlElement signature = signedXml.GetXml();
// Get or create the DigitalSignatureOriginPart.
DigitalSignatureOriginPart dsOriginPart =
openXmlPackage.GetPartsOfType<DigitalSignatureOriginPart>().FirstOrDefault() ??
openXmlPackage.AddNewPart<DigitalSignatureOriginPart>();
var xmlSignaturePart = dsOriginPart.AddNewPart<XmlSignaturePart>();
// Write the Signature XmlElement to the XmlSignaturePart.
using Stream stream = xmlSignaturePart.GetStream(FileMode.Create, FileAccess.Write);
using XmlWriter writer = XmlWriter.Create(stream);
signature.WriteTo(writer);
}
The full source code of the above void Sign(OpenXmlPackage, X509Certificate2) method can be found in my CodeSnippets GitHub repository. Look for the DigitalSignatureManager class in the CodeSnippets project.
Currently we are using a WPF application for creation/editing of List&Label Templates, but we are considering to move to the WebDesigner. Because we use project includes we need to use the repository mode.
I've been trying to import our existing templates, but I run into some issues regarding the RepositoryItemDescriptor. To create a RepositoryItem object you have to give a Descriptor in the constructor, but I cannot find any info regarding how you get it from the generated .lst file.
The data that we have at our disposal are:
TemplateType: List or Form
TemplateData: content of the .lst file (byte[])
IsMainTemplate: bool, is a "project include" or not
File name: name of the .lst file
The RepositoryItem constructor requires: string internalID, string descriptor, string type, DateTime lastModificationUTC.
What I have now is:
public class TemplateBaseModel : RepositoryItem
{
// Properties
// we have our own Ids and modification date, override RepositoryItem properties
public new InternalID => $"repository://{{{Id}}}";
public DateTime LastModificationUTC => ModifiedOn;
public TemplateBaseModel() : base($"repository://{{{Guid.NewGuid()}}}", /* ?? */, RepositoryItemType.ProjectList.Value, DateTime.Now) { }
public TemplateBaseModel(string internalID, string descriptor, string type, DateTime lastModificationUTC) : base(internalID, descriptor, type, lastModificationUTC) { }
}
In the documentation I can only find what it is (internal metadata that is serialized into a string, and can be edited with the class RepositoryItemDescriptor), but not how it's created or how you can get it, and if I try to debug the example I get (in the CreateOrUpdate() method)#2#PgUAAENoS19QYWNrZWQAeNqd1E1PE1EYxfHfmsTvMAyJEeLY8iKCtpChU5MmvAiOC2NcjDCYmqFtZkaEqF9dXThgsTVGt/fm+Z9zz3lyv3/r2HXlQiFwKVeqDI2NdIVWPdIWCuRGTo2dGRp5ryv0Suq5yKpNoUCllhk5kymMjeS6QtdyldCuHfcs6FgUiQQSqUQgEk3dJY70pF57oS8wURo7N1TIBd64Z0GgY1HfodRA6rXAqVIgdN+SK21tbZlnt4o9J41W2OjNo9Qy72Y421OcVGzvD6R9fQcNcdb7A4WhSm3FQ4GhWu7CimUrt6T5rJvJacruHcruHEosldo38PI3ykjmQi7Qk4ilYoElJ/qOvTJwoi+Z4s33daMeeGDJiyna8szs725+zf6vmz8Tf+71U5WJzGmT/5ncucxHhdoXE6VcJVe6lFsWCGdOQzsCb+ds8I3T6R2+2/qv/ZjNvit0IjcxVhmqjZWuDZpXhHfanE2rKzSQCO0o53Ceamn5rGdTrC3Ws6YtkuiJbYts2LJlXWRbbNWayIbEE7E9sZ4Na9Y91vdVR+vWx9+9pa5NmvwKhVaTzQe5U7WWQqX+R+q+TKV20PxI54ZyZ0I7LmXK5t17PkkcOnSkdKxtT6pwLNbVnava0brt6abP1txGfwD+q8AH, which doesn't help either.
Any idea how to properly create a RepositoryItem from a .lst file? or how to create/get the descriptor?
You should try and use the class RepositoryImportUtil from the combit.ListLabel23.Repository namespace. This helper class does all the hard work for you. Given an IRepositoryinterface and the lst file in place, the required code would be something like
IRepository listLabelRepository = <yourRepository>;
using (ListLabel LL = new ListLabel())
{
LL.FileRepository = listLabelRepository;
using (RepositoryImportUtil importUtil = new RepositoryImportUtil(listLabelRepository))
{
importUtil.ImportProjectFileWithDependencies(LL,
#"<PathToRootProject>");
}
}
If this method is not what your require, the helper class has a couple of other methods as well to help you importing existing projects.
With the help of other Stackoverflow users, I have gone some way to my solution but have come to a halt.
I would like to build some generic classes in an app_code .cshtml file eg one would be to return property values from documents from a function eg
public static string docFieldValue(int docID,string strPropertyName){
var umbracoHelper = new Umbraco.Web.UmbracoHelper(Umbraco.Web.UmbracoContext.Current);
var strValue = "";
try{
strValue = umbracoHelper.Content(docID).GetPropertyValue(strPropertyName).ToString();
}
catch(Exception ex){
strValue = "Error - invalid document field name (" + strPropertyName + ")";
}
var nContent = new HtmlString(strValue);
return nContent;
}
This works ok for returning one field (ie property) from a document. However, if I wanted to return 2 or more, ideally, I would store the returned node in a variable or class and then be able to fetch property values repeatedly without having to look up the document with each call
ie without calling
umbracoHelper.Content(docID).GetPropertyValue(strPropertyName).ToString();
with different strPropertyName parameters each time, as I assume that will mean multiple reads from the database).
I tried to build a class, with its properties to hold the returned node
using Umbraco.Web;
using Umbraco.Core.Models;
...
public static Umbraco.Web.UmbracoHelper umbracoHelper = new Umbraco.Web.UmbracoHelper(Umbraco.Web.UmbracoContext.Current);
public static IPublishedContent docNode;
...
docNode = umbracoHelper.Content(docID);
but this crashed the code. Can I store the node in a property on a class, and if so, what type is it?
First of all, using a .cshtml file is unnecessary, use a .cs file instead :-) CSHTML files are for Razor code and HTML and stuff, CS files are for "pure" C#. That might also explain why your last idea crashes.
Second of all, UmbracoHelper uses Umbracos own cache, which means that the database is NOT touched with every request. I would at least define the umbracoHelper object outside of the method (so it gets reused every time the method is called instead of reinitialised).
Also, beware that property values can contain all kinds of other object types than strings.
EDIT
This is an example of the entire class file - my example namespace is Umbraco7 and my example class name is Helpers:
using Umbraco.Web;
namespace Umbraco7
{
public class Helpers
{
private static UmbracoHelper umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
private static dynamic docNode;
public static string docFieldValue(int docID, string strPropertyName)
{
docNode = umbracoHelper.Content(docID);
return docNode.GetPropertyValue(strPropertyName).ToString();
}
}
}
This is an example how the function is called inside a View (.cshtml file inside Views folder):
#Helpers.docFieldValue(1076, "introduction")
Helpers, again, is the class name I chose. It can be "anything" you want. I've just tested this and it works.
I suggest you read up on general ASP.NET MVC and Razor development, since this is not very Umbraco specific.
I want to use a standard dialog to solicit user input of an ADO.net connection string. It is trivial to do for the oledb connection string as described here:
MSDN Article on MSDASC.DataLinks().Prompt
I've also found examples that use Microsoft.Data.ConnectionUI.dll and MicrosoftData.ConnectionUI.Dialog.dll from VS (HOWTO: Using the Choose Data Source dialog of Visual Studio 2005 from your own code).
Unfortunately these DLLs are not licensed for redistribution.
Is there a standard dialog for choosing a data source that can be distributed with my application?
#rathkopf, it looks like these DLLs have been authorized for redistribution since Feb 2010:
http://connect.microsoft.com/VisualStudio/feedback/details/423104/redistributable-microsoft-data-connectionui-dll-and-microsoft-data-connectionui-dialog-dll
http://code.msdn.microsoft.com/Connection
The source code for these DLLs is now available: http://blogs.msdn.com/b/vsdata/archive/2010/02/02/data-connection-dialog-source-code-is-released-on-code-gallery.aspx
Also you can do this programmatically using the DataLink Properties:
Add the reference to ADODB.DLL (from .NET reference) and Microsoft OLE DB Service Component 1.0 Type Library from the COM tab in your visual studio reference tab.
using ADODB;
using Microsoft.Win32;
public partial class ConnectionStringStep : Form
{
private const string MSSQL_PROVIDER = "Provider=SQLOLEDB.1";
private const string ORACLE_PROVIDER = "Provider=MSDAORA.1";
private const string MSSQL = "MSSQL";
public ConnectionStringStep()
{
InitializeComponent();
}
private static string DataBaseType()
{
//get the data from some previous screen or some kind of storage
return MyStorage.GetProperty("DATABASE_TYPE") ?? "MSSQL";
}
private void button1_Click(object sender, EventArgs e)
{
var dataBaseType = DataBaseType();
var adodbConnection = new Connection
{
ConnectionString = dataBaseType == MSSQL ? MSSQL_PROVIDER : ORACLE_PROVIDER
};
object connection = (object) adodbConnection;
var dialog = new MSDASC.DataLinks();
dialog.PromptEdit(ref connection);
connectionTextBox.Text = adodbConnection.ConnectionString;
}
}
DataLink Properties Reference
There is now a NuGet package by Microsoft providing this dialog:
DataConnectionDialog.
Sample usage:
var dialog = new DataConnectionDialog();
dialog.DataSources.Add(DataSource.SqlDataSource);
dialog.ConnectionString = connectionString;
if (DataConnectionDialog.Show(dialog) == System.Windows.Forms.DialogResult.OK)
{
connectionString = dialog.ConnectionString;
}
It's related, but I'm now sure how you can embed this behavior inside your application.
Every time I need one, I create an empty text file, changed its file extension to ".udl" and double-click it; when I'm done, I close that application, rename that file back to ".txt" and open with Notepad.
It appears that such a beast does not exist. I've written my own dialog and can include it in projects as needed.
Update:
The source code for these DLLs are now available as per #code4life's answer.