I have a reporting module in an ASP.NET webforms app (C#) that uses dynamic controls for the parameters for each report.
These dynamic controls are built from an XML column in a SQL Server 2008 DB.
XML structure:
<Report Parameters>
<Parameter>
<Name>CustomerId</Name>
<Control />
</Parameter>
<Parameter>
<Name>Start Date</Name>
<Control>DDL</Control>
</Parameter>
</Report Parameters>
I've left out a lot of the elements for readability.
If the <Control> element is not empty (as in the case of the Start Date parameter in the XML example) then a C# based XSLT tranformation creates the appropriate control on my form .
If the <Control> element is empty (as in the case of the CustomerId) then I want to use an existing c# property with the same name (i.e. I have a CustomerId defined in my c# code).
These parameter values (CustomerId and Start Date) are then passed to a stored procedure used to generate the report data.
I use the XPathNavigator and associated classes in my C# code to yank out the <Name> element of any <Control> element that is empty.
The problem is that the <Name> element is in the form of a string and I really want it to be in C# code form (sorry can't think of a better way to describe this!) i.e. I want this.CustomerId (added the this to show it's code not a string) not "CustomerId".
As I don't know how many reports this system will have over time I don't really want to build up an enum or switch statement if "CustomerId" then this.CustomerId etc. as it seems to negate the point of dynamic code.
I realise that reflection will probably be needed and I have little knowledge of this so any advice or advice on a different approach to this problem would be welcome.
Thanks,
Rich.
What you are looking for is a Code generator. While I haven't implemented one myself, I have used templates created by others before and it works like a charm. You can get started here.
You want to dynamically generate a class and it's properties based on the xml contents?
And you want it without having to generate code and recompile i'm sure too.
I have tried that too once and i never managed to get it working.
I don't see any solution, sorry.
This should do it:
this.GetType().GetProperty("CustomerId").SetValue("YourValue");
Related
The question I have is whether it is possible either in C# using native or other APIs or in SQL Server to access a SQL query's metadata.
Finding the schema information is easy enough when dealing with a standard SELECT statement, but it becomes more difficult when doing something along the lines of:
SELECT COUNT(DISTINCT [ColumnA]) as 'CountResult'
FROM MyTable
The goal being to find out the source column(s) for CountResult or even just the statement that created the alias.
This may help: SqlDataReader.GetSchemaTable();
Dynamic Management Views (DMVs) also provide quite a bit of system information. To get a quick list, you can run this query list in this blog. The DMV names are pretty self-explanatory.
Not sure that this helps, but you can get some info in execution plan. For example, execute you query with SET SHOWPLAN_XML ON statement before. It returns xml with detailed info about statement. The only problem is, that there is a lot of info, so your simple query sample will get this such code for list of output columns.
<OutputList>
<ColumnReference Column="Expr1234" />
</OutputList>
By looking the Expr1234 you can find that result from Expr2345 is casted to int:
<ColumnReference Column="Expr1234" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(int,[Expr2345],0)">
<Convert DataType="int" Style="0" Implicit="1">
<ScalarOperator>
<Identifier>
<ColumnReference Column="Expr2345" />
</Identifier>
</ScalarOperator>
</Convert>
</ScalarOperator>
Next step will be to find Expr2345, where you can get that this is:
<ColumnReference Column="Expr2345" />
<ScalarOperator ScalarString="Count(*)">
<Aggregate AggType="countstar" Distinct="0" />
</ScalarOperator>
So if you need exact column statement as it was in query, it will be hard to get it from plan. But if custom format allowed, just to get understanding what happens in column, this way might helps.
I know that this question seems illogical, but I have to try, and I hope to find a way,
I've a DLL assembly reading a variable, "GalleryID", from an XML file. I can't modify the assembly, so I am wondering if I can make the XML element value dynamic? For example, to get this value from a querystring or any other scenario without changing the assembly.
In Settings.xml:
< ?xml version="1.0" encoding="utf-8"? >
< GallerySettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
< GalleryID >2< /GalleryID > // Here I would like this value to be dynamic, not static like this.
< /GallerySettings >
In mylibrary assembly:
protected static XmlDocument myXmlDoc;
' in Page_Load ev mylibrary
MyLibrary.myXmlDoc.Load(base.Server.MapPath("Conntrols/Settings.xml"));
XmlNode documentElement = MyLibrary.myXmlDoc.DocumentElement;
MyLibrary.myappSettings.GalleryID = documentElement.SelectSingleNode("GalleryID").ChildNodes[0].Value.ToString();
This is an ASP.NET website that has multiple users. When a user logs in and open the gallery.aspx page it will show the user's own gallery. This scenario is not working now since the gallery module shows one gallery (Galleryid=2) to all users according to its setting in Settings.xml file. How can I pass galleryid in querystring -- gallery.aspx?galleryid=5 and inject it to Settings.xml file?
Is that possible?
I am going to restate what I understand from your question to make sure I 'get it'.
You have an assembly (from a .dll) that reads an XML file as a data source to get the "GalleryID" out of a node that looks like: <GalleryID>2</GalleryID>
You want to be able to change the GalleryID before the assembly reads it.
I assume (yes, dangerous...) that you are invoking your assembly from an application that you DO have control over. (Since, presumably you don't have control over the assembly that reads the XML doc.) This would be the calling context, and the host that defines exactly where the "Server" in Server.MapPath is going to look for "Conntrols/Settings.xml"
There are two basic solutions that come to mind:
Open the XML document, change the value and save it from your calling context.
Swap out XML document "settings.xml.alt" for "settings.xml" from your calling context.
Would this not be better off being done in an in-process database?
You are explaining to me that you are going to have a lot of different galleries. In this way, with that much dynamic data, I think you would be better to use an in-process database such as SQL Server Compact and could be easily done using the Entity Framework code. First, get the package off of NuGet. If you have control over your data source I would personally go this route.
I could use a little guidance on working with XML.
I'm working on a several XML interop specifications which will be used to create or update data in our system. I'd like to provide a way for my customers to specify which elements they want to maintain via automation using the XML spec vs. manually updating the records after the fact. The quick back story to this is that our customers have upstream applications that can supply some but typically not all of the data required by our application so they will typically be sending us partial information for a record and then maintaining the rest in our app.
So assuming a simple XML:
<Data>
<Element1 />
<Element2 />
<Element3 />
</Data>
Customer A may supply element 1 and 2 but not element 3 so they would want to configure 3 to persist values between updates but for 1 and 2 to always overwrite with the new value.
Customer B may supply element 1, 2 and 3 and want to configure to always overwrite all 3 elements.
So I guess what I'm really looking for with Customer A is something like this:
<Data>
<Element1>data1</Element1>
<Element2>data2</Element2>
<Element3 overwriteExistingData="false"></Element3>
</Data>
I understand XML to a degree but have found it very easy to create an XML schema by simply creating C# class, doing some decorating with attributes if necessary and then generating a schema with xsd.exe and calling it a day.
Things that I'm unsure of are
- how to distinguish between a null value and something that the customer didn't have a value for
- the best way to handle these partial data situations where I'm not going to get a complete replacement record for every update.
I'm sure I am missing the boat to some degree but I really like the simplicity of having a class definition and telling the customer to give me XML that allows me to just type one line of code to deserialize the XML into my C# object.
Any guidance would be much appreciated
We are communicating with a 3rd party service using via an XML file based on standards that this 3rd party developed. They give us an XML template for each "transaction" and we read it into a DataSet using System.Data.DataSet.ReadXML, set the proper values in the DataSet, and then write the XML back using System.Data.DataSet.WriteXML. This process has worked for several different files. However, I am now adding an additional file which requires that an integer data type be set on one of the fields. Here is a scaled down version:
<EngineDocList>
<DocVersion>1.0</DocVersion>
<EngineDoc>
<MyData>
<FieldA></FieldA>
<FieldB></FieldB>
<ClientID DataType="S32"></ClientID>
</MyData>
</EngineDoc>
</EngineDocList>
When I look at the DataSet created by my call to ReadXML to this file, the MyData table has columns of FieldA, FieldB, and MyData_ID. If I then set the value of MyData_ID and then make the call to WriteXML, the export XML has no value for ClientID. Once again, if I take a way the DataType, then I do have a ClientID column, I can set it properly, and the exported XML has the proper value. However, the third party requires that this data type be defined.
Any thoughts on why the ReadXML would be renaming this tag or how I could otherwise get this process to work? Alternatively, I could revamp the way we are reading and writing the XML, but would obviously rather not go down this path although these suggestions would also be welcome. Thanks.
I would not do this with a DataSet. It has a specific focus on simulating a relational model. Much XML will not follow that model. When the DataSet sees things that don't match it's idea of the world, it either ignores them or changes them. In neither case is it a good thing.
I'd use an XmlDocument for this.
I have a list with 2 text fields, and a choice field. How do I use the Lists.asmx web service to insert a new item? I can make a web reference to the lists.asmx service, so you can assume that this is known.
I would like a complete example including code and the XML for the CAML query. Ideally the sample would use C#.
Using the Lists web service to insert item into a SharePoint list can indeed be tricky. Since this method is of the form: XML in, XML out, it can be hard to get the parameters right.
First you should take a look at the list definition. It can be retrieved with the method GetList(), as shown below:
XmlNode listXml = sharePointLists.GetList(listName);
File.WriteAllText("listdefinition.xml", listXml.OuterXml);
Important here are the names of the fields and their data types. Field names will never be the same as the ones you see in the SharePoint GUI. A good example is the Title field which is used for the first field of the list.
Now that you know that, you can create the query to go to SharePoint. An example:
<Batch OnError="Continue">
<Method ID="1" Cmd="New">
<Field Name="Title">Abcdef</Field>
<Field Name="Project_x0020_code">999050</Field>
<Field Name="Status">Open</Field>
</Method>
</Batch>
The Batch element is the root element of the XML. Inside you can put different Methods. These should get a unique ID (which is used to report errors back to you) and a command, which can for instance be "New" or "Update". Inside the Method, you put Field elements that specify the value for each field. For instance, the Title field gets the value "Abcdef". Be careful to use the exact name as it is returned by GetList().
To execute the query on SharePoint, use the UpdateListItems() method:
XmlNode result = sharePointLists.UpdateListItems(listDefinition.Name, updates);
The return value is an XML fragment containing the status of each update. For instance:
<Results xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Result ID="1,New">
<ErrorCode>0x00000000</ErrorCode>
<z:row ows_ContentTypeId="0x010036F3F587127F1A44B8BA3FEFED4733C6"
ows_Title="Abcdef"
ows_Project_x0020_code="999050"
ows_Status="Open"
ows_LinkTitleNoMenu="Abcdef"
ows_LinkTitle="Abcdef"
ows_ID="1005"
...
xmlns:z="#RowsetSchema" />
</Result>
</Results>
You can parse this and look at the ErrorCode to see which methods failed.
In practice I have created a wrapper class that takes care of all the dirty details for me. Unfortunately this is owned by my employer so I cannot share it with you.
This wrapper class is part of an internal utility that is used to retrieve information from our project database and post it to SharePoint. Since it was developed during company time, I'm not allowed to post it here.