Adding comments using XDT-Transform - visual-studio-2010

I am using XDT-Transform in Visual Studio 2010 to generate multiple config files.
Xml transformation is working fine. But I cannot seem to find way to carry comments from an xml transform file to final file.
Just like there is Insert transform for adding config settings, is there anyway to add comments? Without comments I may have to give up on the whole transform approach.

I've found a possible solution for you.
It is only necessary to denote something as being an Insert at the highest level you are adding it. After that you may just add elements like you would normally.
Meaning this doesn't work to bring over your comment
<appSettings>
<!--My Secret Encryption Key-->
<add key="ENCRYPT_KEY" value="hunter2" xdt:Transform="Insert" />
</appSettings>
But this would
<appSettings xdt:Transform="Remove" />
<appSettings xdt:Transform="Insert" >
<!--My Secret Encryption Key-->
<add key="ENCRYPT_KEY" value="hunter2"/>
</appSettings>
Nothing else requires a transform as it copies over the element entirely.
Upside: You get your comments and don't have to insert xdt:Transform="Insert" into every key element.
Downside: You end up destroying the section entirely and re add it which ends up appending it to the bottom of your Web.config. If the change in total formatting is okay then awesome. Also it requires you recreate the entire section which could increase the size of your transforms.

This isn't exactly what you want, but I find it useful once in a while.
XmlTransform will add comments if they are contained in an added element.
e.g.
<appSettings>
<remove key="comment" value="" xdt:Transform="Insert"><!-- this comment will appear in the transformed config file! --></remove>
</appSettings>

Not possible without writing code.
However, my current solution is to extent the XDT Transform library, by basically following the link: Extending XML (web.config) Config transformation
And here is my example of CommentAppend, CommentPrepend which take comment text as input parameter, as I believe otherwise Insert itself can't work as the comment you would put your xdt:Transform="Insert" will be ignored by XDT Transform as it is comment.
internal class CommentInsert: Transform
{
protected override void Apply()
{
if (this.TargetNode != null && this.TargetNode.OwnerDocument != null)
{
var commentNode = this.TargetNode.OwnerDocument.CreateComment(this.ArgumentString);
this.TargetNode.AppendChild(commentNode);
}
}
}
internal class CommentAppend: Transform
{
protected override void Apply()
{
if (this.TargetNode != null && this.TargetNode.OwnerDocument != null)
{
var commentNode = this.TargetNode.OwnerDocument.CreateComment(this.ArgumentString);
this.TargetNode.ParentNode.InsertAfter(commentNode, this.TargetNode);
}
}
}
And the input web.Release.config:
<security xdt:Transform="CommentPrepend(comment line 123)" >
</security>
<security xdt:Transform="CommentAppend(comment line 123)" >
</security>
And the output:
<!--comment line 123--><security>
<requestFiltering>
<hiddenSegments>
<add segment="NWebsecConfig" />
<add segment="Logs" />
</hiddenSegments>
</requestFiltering>
</security><!--comment line 123-->
I am currently using Reflector to look at Microsoft.Web.XmTransform comes with Visual Studio V12.0 to figure out how it works, but probably it's better to look at the source code itself

As far as I am aware adding comments using XDT-Transform is not possible I'm afraid.
At least it doesn't appear to be mentioned within the XDT-Transform documentation

I built an extension for XDT to handle comment injection and other related tasks.
You can try it online.

Related

ColdFusion Proxy Server

I'm trying to create a basic proxy server so I can keep track of what my kids are doing web wise - I know there are products out there but I thought it would be an interesting exercise to write one myself.
I have the following code that kind of works but doesn't pull any images or css through - I guess because it makes another call to the remote server and gets confused
<cfhttp url="https://www.bbc.co.uk">
<cfhttpparam type="header" name="Proxy-Connection" value="keep-alive" >
<cfhttpparam type="header" name="Accept" value="application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5">
<cfhttpparam type="header" name="Accept-Language" value="en-US,en;q=0.8">
<cfhttpparam type="header" name="Accept-Charset" value="ISO-8859-1,utf-8;q=0.7,*;q=0.3">
</cfhttp>
<cfset html = cfhttp.FileContent />
<cfoutput>#html#</cfoutput>`
What am I missing?
What you want to use is the resolveurl parameter of - set it to yes/true. This defaults to no.
What this parameter does is resolves relative paths to absolute paths automatically for you.
Now, if you want to change those paths as well, you would change them to also route through your http proxy script, but there won't be much use as you won't know much about the content regardless.
resolveurl should hook you up with what you are looking for. cheers.
https://cfdocs.org/cfhttp (look for resolveurl tag attribute)

Get the SSIS Event Name in Script Task

I am wanting to run a standard script task in package level events (OnError, OnPreExecute, OnPostExecute) for logging.
Ideally I would like to be able to just copy and paste the Script task, but it needs to know the Event that it is running inside of. Currently I pass that in as a use variable, but this means that I need to manually set the variable to store the name of the event. That's not too arduous, but it is easily forgotten. Thus my question is, is there a performant way to detect which event the script task is running within.
My suspicion is that this is not easy as essentially this is the same as finding out the name of the parent container, which turns out to be next to impossible.
Another option is to be able to sniff the scope of standard event variables, such as 'EventHandlerStartTime', but I can't find a way to determine the scope of a variable from within the script task.
Any help is much appreciated.
Since #Mark mentioned Biml, I thought I'd take a moment to explode out the concept of using some very basic concepts to make this happen.
Assuming I had a pathetic logging table like
CREATE TABLE
dbo.DoWhat
(
PackageName nvarchar(150) NULL
, ParentContainerGUID varchar(38) NULL
, SourceDescription nvarchar(1000) NULL
, SourceName nvarchar(150) NULL
, SourceParentGUID varchar(38) NULL
, EventName varchar(20) NULL
);
then I could define a "function" in a file called inc_events.biml
What that says, this file expects a parameter of type string that will populate the eventName variable. I then use a classic ASP style syntax for subbing in that value <#=eventName#>
So, this biml will create an Event. That event has a Variable named WhereAmI that is scoped to the Event. I then have an Execute SQL Task in there that does an insert into the logging table passing along System variables and my local variable name.
You're looking to use a Script Task so you'd replace the Execute SQL Task but the concept is the same. There's a something in there that's going to use our local variable that had the event's name assigned to it.
<## property name="eventName" type="String" #>
<Event EventType="<#=eventName#>" ConstraintMode="Linear" Name="<#=eventName#>">
<Variables>
<Variable DataType="String" Name="WhereAmI"><#=eventName#></Variable>
</Variables>
<Tasks>
<ExecuteSQL ConnectionName="tempdb" Name="SQL Log notes">
<VariableInput VariableName="User.QueryLog"></VariableInput>
<Parameters>
<Parameter DataType="String" VariableName="System.PackageName" Name="0" />
<Parameter DataType="AnsiString" VariableName="System.ParentContainerGUID" Name="1" DataTypeCodeOverride="129" />
<Parameter DataType="String" VariableName="System.SourceDescription" Name="2" />
<Parameter DataType="String" VariableName="System.SourceName" Name="3" />
<Parameter DataType="AnsiString" VariableName="System.SourceParentGUID" Name="4" DataTypeCodeOverride="129" />
<Parameter DataType="AnsiString" VariableName="User.WhereAmI" Name="5" DataTypeCodeOverride="129" />
</Parameters>
</ExecuteSQL>
</Tasks>
</Event>
Using the include file
I add a second Biml file, so_27378254_inc.biml to my project. This one is going to demonstrate how we use the function/include file.
I define an OLE DB database connection in Connections collection called tempdb
In my Packages collection, I define a new package called so_27378254_inc. It has a Variable, QueryLog which just contains the format for an insert statement into my log table.
In the package's Events collection, I then invoke CallBimlScript 3 times, one for each Event Handler I want to add at the package level scope.
Into the Tasks collection, I add a Sequence Container just so I can get some variety in my log.
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection Name="tempdb" ConnectionString="Data Source=localhost\dev2014;Initial Catalog=tempdb;Provider=SQLNCLI10.1;Integrated Security=SSPI;" />
</Connections>
<Packages>
<Package ConstraintMode="Linear" Name="so_27378254_inc">
<Variables>
<Variable DataType="String" Name="QueryLog">
<![CDATA[INSERT INTO
dbo.DoWhat
(
PackageName
, ParentContainerGUID
, SourceDescription
, SourceName
, SourceParentGUID
, EventName
)
SELECT
? /* AS PackageName */
, ? /* AS ParentContainerGUID */
, ? /* AS SourceDescription */
, ? /* AS SourceName */
, ? /* AS SourceParentGUID */
, ? /* AS EventName */
;]]>
</Variable>
</Variables>
<Events>
<#=CallBimlScript("inc_events.biml", "OnError")#>
<#=CallBimlScript("inc_events.biml", "OnPreExecute")#>
<#=CallBimlScript("inc_events.biml", "OnPostExecute")#>
</Events>
<Tasks>
<Container Name="SEQC Container on Control Flow" ConstraintMode="Linear">
</Container>
</Tasks>
</Package>
</Packages>
</Biml>
So, what do you do with it? You right click on the so_27378254_inc.biml file and whoosh, a new package is generated.
How the heck do I sell this?
You mention in your comments, and rightfully so, concerns over anything that would "add friction to adoption".
My counter to that is
BIDS Helper is free and if you're not using it, you're not being as effective in your delivery as you could be. Especially pre-2012, there's just too many sharp edges in the product.
Using an approach like this will get everyone to a consistent starting point, without some of the hassles that come with template packages (IDs are not automatically updated until 2012)
You don't have to go all in on the Biml approach. Assuming you're the architect/lead developer, use it to define best practices. Everyone has logging turned on, apply configurations, get the standard connections defined, etc. All people have to do is instead of creating new SSIS, they right click and generate the template package and then rename it to something appropriate and they're off the races worrying about data flows and file acquisition, etc.

How do I add a script bundle conditionally?

I have a javascript bundle that I only want to include when testing, not when the code is deployed to production.
I have added a Property called IsEnabledTestingFeatures. In the BundleConfig.cs file I access it like so:
if(Properties.Settings.Default.IsEnabledTestingFeatures) {
bundles.Add(new ScriptBundle("~/bundles/testing").Include("~/Scripts/set-date.js"));
}
This works correctly.
Now, I only want to include the bundle in my page if this property is set to true.
I have tried the following, but the compiler is complaining that it cannot find the Default namespace:
#{
if( [PROJECT NAMESPACE].Properties.Default.IsEnabledTestingFeatures)
{
#Scripts.Render("~/bundles/testing")
}
}
I tried finding how to access the Scripts.Render functionality from the Controller itself, but have been unsuccessful.
I prefer to add the bundle in the view itself, but will settle for adding it via the Controller.
The ViewBag should not be necessary...
Using appSettings from web.config you don't need to recompile for testing and it deploys easily.
<appSettings>
<add key="TestingEnabled" value="true" />
</appSettings>
View or Layout
#{
bool testing = Convert.ToBoolean(
System.Configuration.ConfigurationManager.AppSettings["TestingEnabled"]);
}
#if (testing) {
#Scripts.Render("~/bundles/testing")
}
And I would define "~/bundles/testing" in BundleConfig regardless of the testing condition unless you wish to bundle this with other scripts.
If you assigned Properties.Default.IsEnabledTestingFeatures from AppSettings then the root of your problem is how you implemented your Properties.
Until, hopefully, an alternative [read: better] solution is proposed, I have implemented it using ViewBag.
BundleConfig.cs
//if testing features are enabled (eg: "Set Date"), include the necessary scripts
if(Properties.Settings.Default.IsEnabledTestingFeatures)
{
bundles.Add(new ScriptBundle("~/bundles/testing").Include(
"~/Scripts/set-date.js"));
}
Controller
public ActionResult Index()
{
ViewBag.IsEnabledTestingFeatures = Properties.Settings.Default.IsEnabledTestingFeatures;
return View();
}
View
#if (ViewBag.IsEnabledTestingFeatures != null && ViewBag.IsEnabledTestingFeatures)
{
#Scripts.Render("~/bundles/site")
}
Some Notes:
I did not implement this via a property in the ViewModel due to this
property/feature being independent of the data being displayed. It
seemed incorrect to associate this condition with individual data
models as it is a site-wide feature.
I used application-level settings because it will be easier to configure this property on a per-environment basis due to the fact we utilize web transforms. Thus each environment can set this property as needed.

Is there any way to have Visual Studio ignore the <devdoc> tag when compiling?

Basically, I was attempting to keep all of my documentation in a separate file and use the <include> tag. This would let me keep my source code free of documentation clutter. I still wanted a way to have some developer notes about classes and members, so I used the <devdoc> tag. The problem is now Visual Studio adds my developer notes to the xml documentation file. Is there any way to not have it compile into the xml documentation?
/// <devdoc>This is an interesting Foo class</devdoc>
/// <include file="docs.xml" path='Doc/Member[#for="MyNamespace.Foo"]/*' />
public class Foo { ... }
Which resulted in:
<member name="T:MyNamespace.Foo">
<devdoc>This is an interesting Foo class</devdoc>
<Summary>Some summary for testing.</Summary>
</member>
I realize that Sandcastle is not going to use the <devdoc> class when it generates its documentation, but if I want to give intellisense information about my library I need to include the generated xml file. If it's impossible, it's not the end of the world, but I'm hoping that there is a way to exclude it to begin with.
I would create a simple console application that would be called from a post-build event. The application will remove all <devdoc> tags. It can be really simple. Just read the generated XML file and use regex like this:
using System.Text.RegularExpressions;
Regex regex = new Regex("<devdoc>(.|\n)*</devdoc>", RegexOptions.Compiled | RegexOptions.Multiline);
s = regex.Replace(s, string.Empty);
You can also use XmlDocument and its GetElementsByTagName method and then XmlNode.RemoveChild to remove the tags. But I believe regex would be more efficient.

Dynamic LINQ context

I'm trying to figure out how to create a dynamic context, and what I mean by that is I have two databases: one for testing, and one for production. Depending on where my website is hosted, I want my context to be pointing at one of the two. So, in my web.config I have:
<add name="Testing_ChannelsEntities" connectionString="removed for brevity" providerName="System.Data.EntityClient" />
<add name="Production_ChannelsEntities" connectionString="removed for brevity" providerName="System.Data.EntityClient" />
Please don't get hung-up on the fact that I removed the connectionString for this example. Just note that I have a testing and a production connection in the web.config.
So, here is my codebehind that I would expect to create a context to the testing connectionString:
using (ChannelsEntities chEntity = new ChannelsEntities("Testing_ChannelsEntities")) {
// removed the business logic because it's not relevant at all
}
Once execution hits the using statement, I get the following error:
Format of the initialization string does not conform to specification starting at index 0.
What am I missing here? This should be easy to do.
I've done similar. Try this -
using (ChannelsEntities chEntity = new ChannelsEntities("name=Testing_ChannelsEntities")) {}
Try:
using (ChannelsEntities chEntity = new ChannelsEntities(WebConfigurationManager.ConnectionStrings["Testing_ChannelsEntities"].ConnectionString)) {
// removed the business logic because it's not relevant at all
}
We put our connection string in a root web.config. You can reference the connection string by name in your virtual diectory and it will inherit the settings from your root web.config.

Resources