public
{
fName +=
xDoc.Load(fName);
}
static string GetAppConfig(string key)string fName = Assembly.GetExecutingAssembly().Location.Substring(0,Assembly.GetExecutingAssembly().Location.LastIndexOf("\\"));"\\MyApp.exe.config";XmlDocument xDoc = new XmlDocument();XmlNode xNode = xDoc.SelectSingleNode("/configuration/appSettings");XmlNode keyNode = xNode.SelectSingleNode(string.Format("//add[@key='{0}']", key));return keyNode.Attributes["value"].Value;
I have noticed an anamoly with doing XML Transformations in .Net. If the XSLT marks specific sections as CDATA, the output seems to missing that.
Example:
XSLT:
<
xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" cdata-section-elements="EMPLAST EMPFIRST"/>
We would expect output to be of the format:
<Employee>
<EMPLAST><![CDATA[John]]></EMPLAST>
and so on...
</Employee>
However, the standard XSLT transformation does not output the CDATA bit, when done through .Net, so what you get is
<EMPLAST>John</EMPLAST>
This because the default example on MSDN uses an XmlWriter that will, guess what, write the xml text as, well ... xml and hence ignore the CDATA sections!! To properly write out the transformed text, use a TextWriter and all will be well again....
A complete example is given below:
using
System;
using
System.Collections.Generic;
using
System.IO;
using
System.Text;
using
System.Xml;
using
System.Xml.XPath;
using
System.Xml.Xsl;
using
System.Xml.Schema;
....
public static string TransformXml(string xml, string xsl)
{
/* Load the xml into an XmlReader*/
XmlReader rXml = CreateXmlReaderFromString(xml);
/* Load the xsl into an XmlReader*/
XmlReader rXsl = CreateXmlReaderFromString(xsl);
Stream oStream = new MemoryStream();
using (TextWriter tr = new StreamWriter(oStream, outputEncoding))
{
/* Create a XslCompiledTransform class to do the transformation */
XslCompiledTransform trans = new XslCompiledTransform();
trans.Load(rXsl);
trans.Transform(rXml,
null, tr);
// declare a buffer to hold the contents of the stream
byte[] arrBuffer = new byte[oStream.Length];
// we have to set the position to 0 so that it moves the pointer back to
// the start of where we want to read
oStream.Position = 0;
// read from the stream to our buffer
int iLastLength = oStream.Read(arrBuffer, 0, (int)oStream.Length);
// have we read anything
if (iLastLength > 0)
{
// get our transformed xml using our encoder and the buffer
xml = outputEncoding.GetString(arrBuffer);
}
else
{
xml =
string.Empty;
}
}
return xml;
}
private
static XmlTextReader CreateXmlReaderFromString(string XML)
{
XmlTextReader xmlReader = null;
StringReader sReader = new StringReader(XML);
xmlReader =
new XmlTextReader(sReader);
return xmlReader;
}
The following is a handy piece of code for extracing an embedded stream of characters from your assembly and saving to a text file.
1. Set the resource to Embedded.
2. Copy the following piece of code:
public
static void WriteResourceToFile(string resourceName, string fileName)
{
using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
if (s != null)
{
byte[] buffer = new byte[s.Length];
char[] sb = new char[s.Length];
s.Read(buffer, 0, (
int)(s.Length));
/* convert the byte into ASCII text */
for (int i = 0; i <= buffer.Length - 1; i++)
{
sb[i] = (
char)buffer[i];
}
using (StreamWriter sw = new StreamWriter(fileName))
{
sw.Write(sb);
sw.Flush();
}
}
}
}
I hope the following will save you some time when dealing with custom windows installers.
If you want to access the installation path in your customer installer class, your first instinct might be to use a [TARGETDIR] or [INSTALLDIR]
as a custom action (for example /DIR=[TARGETDIR]) and attempt to access that in your custom installer class (for example. dir = Context.Parameters[“DIR”]). This will fail, since the TARGET is populated AFTER the custom action is executed.
I printed out the contents of the Context's parameter collection, that is available to the Custom Action, as shown below:
Writing the contents of the Installation Context
------------------------------------------------------------
Key: [dir] Value:
Key: [action] Value: install
Key: [installtype] Value: notransaction
Key: [assemblypath] Value: C:\Program Files\Company\Company Product\CompanyProduct.exe
Key: [logfile] Value:
------------------------------------------------------------
As seen above, you do have access to the [AssemblyPath] in the Custom Action and by stripping of the product.exe filename,
you can get the directory.
Here is a simple function that will achieve this:
private
string StripDir(string fullPath)
{
string retValue = default(string);
if (fullPath != null && fullPath != string.Empty && fullPath != default(string))
{
retValue = fullPath.Substring(0, fullPath.LastIndexOf(@"\"));
}
return retValue;
}
So the final code will look like this:
string installDir = StripDir(Context.Parameters[“AssemblyPath“]);
The query below shows how to create an XML document using FOR XML from a table (based on Sql Server 2000). To start with, run the sql script further below to create the sample table, and populate it with some data. Once the select script is run, data will be returned in the form:
<Employees>
<Employee>
<field1></field1>
...
</Employee>
</Employees>
Query
select 1 as Tag,
NULL as Parent,
NULL as [Employees!1!Employee!xml],
NULL as [Employee!2!OfficerId!xml],
NULL as [Employee!2!GivenName!xml],
NULL as [Employee!2!Surname!xml],
NULL as [Employee!2!LoginCode!xml],
NULL as [Employee!2!IsActive!xml]
UNION ALL
select 2,
1,
NULL,
Officer_ID,
Officer_Given_Names,
Officer_Surname,
CRTS_Login_Code,
Is_Active
from staging.dbo.tbl_Officer
for xml explicit
Table
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_Officer]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[tbl_Officer]
GO
CREATE TABLE [dbo].[tbl_Officer] (
[Officer_ID] [int] NOT NULL ,
[Officer_Given_Names] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Officer_Surname] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[CRTS_Login_Code] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Is_Active] [tinyint] NOT NULL
) ON [PRIMARY]
GO
I recently implemented a custom role provider for an asp.net project and discovered an interesting point.
I had to instantiate a role business component in the custom provider class like so:
public
class MyRoleProvider : RoleProvider
{
BLRole blRole = null;
public MyRoleProvider()
{
blRole = new BLRole();
}
All I could see on at runtime was:
Parser Error Message: Exception has been thrown by the target of an invocation.
I moved the instantiation code into the Initialize block and hey pretso, the IDE now told what was causing my error, ie the precached version of my business logic component was throwing the error!
public
override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
// Verify that config isn't null
if (config == null)
throw new ArgumentNullException("config");
// instantiate the role business component
blRole =
new BLRole();
I got the above error message when uninstalling a Windows Service setup from the Add/Remove option.
If you ever get an error message like above, then one or dependent assemblies for your installed application may be missing. Try to locate and install the dependent assemblies manually and then Remove the project using the Add/Remove option.
HTTP GET/POST are disabled by default on web servers in the new .NET 1.1 which could make creating REST-type web services more difficult. The error message you get is:
Request format is unrecognized.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
The fix is to enable GET/POST. See http://support.microsoft.com/default.aspx?scid=kb;en-us;819267 to enable it.
Script to search in stored procs
select upper(SysObjects.Name),SysComments.Text
from SysObjects, SysComments
where SysObjects.type='P'
and (SysObjects.ID = SysComments.ID)
and SysComments.Text like '%SearchString%'
I ran across this weird problem while debugging a stored procedure in Sql Server 2000.
Here's a sample stored procedure:
drop procedure p1
go
create procedure p1
as
create table #t1(
col1 int identity(1,1),
col2 datetime,
col3 int
)
select *
from #t1
return
update #t1
set col3 = col2
return
Ok, notice that I have a return statement after the first select. That is my exit point for now because I am debugging so I am not interested in the section after that. Also notice that the update statement will throw an error like so:
Disallowed implicit conversion from data type datetime to data type int, table 'tempdb.dbo.#t1_________________________________________________________________________________________________________________000100004066', column 'col3'. Use the CONVERT function to run this query.
Now, logically if I run my stored procedure, I know that I will return after the first select statement and I should not get a runtime error at all, but what really happens, is that executing the stored proc throws an error at runtime on a block of code that will never be run! Go figure!
The obvious solution is to either comment out the offending code, or to fix it first before running the SP.
"XML attributes may not be specified for the type"XmlSerializer and CollectionBase derived classesI get this error when I try to serialize an object that is based upon the CollectionBase class and has an XmlRoot attribute.
The solution is to provide hints in the Serialization method to add a defined root in the generated XML. Thanks to user "armanddp"
http://dotnet.org.za/armand/archive/2004/09/21/4164.aspx, I have beautified his solution as shown below:
Step 1: Create an attribute class that you can use to specifiy the root attribute.
[AttributeUsage(AttributeTargets.Class)] public class XmlRootNameAttribute : Attribute { public XmlRootNameAttribute() {} public XmlRootNameAttribute(string name) { this.name = name; } public string name = string.Empty; }Step 2: Add the attribute to your own class.
[Serializable][XmlRootName("StepClassConfigurationCollection")]public class MyCollection : CollectionBase, IList {}Step 3: Create a Serializer method to read the extra attribute, if it exists, otherwise serialise as per normal.
/// <summary> /// Serialize the given object into a string /// </summary> /// <param name="o"></param> /// <returns></returns> public string SerializeObject(object o) { string ret = string.Empty; Stream writer = new MemoryStream(); XmlSerializer ser = null; XmlRootAttribute ra = new XmlRootAttribute(); Type objectType = o.GetType(); // determines if the custom attribute was found bool bAttFound = false; ra.Namespace = string.Empty; // try and find the custom attribute that will determine the root namespace. object [] oAtt = objectType.GetCustomAttributes(typeof(PMPDO.XmlRootNameAttribute), false); if (oAtt != null) { if (oAtt.Length > 0) { bAttFound = true; // use the given root name ra.ElementName = ((PMPDO.XmlRootNameAttribute)oAtt[0]).name; } } if (!bAttFound) { // if there is no root name provided, then just use the default ser = new XmlSerializer(objectType); } else { // otherwise use the provided root name ser = new XmlSerializer(objectType, ra); } XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("",""); if (bAttFound) { // use the given root when provided ser.Serialize(writer, o, ns); } else { // otherwise use the default (no root provided) ser.Serialize(writer, o); } // read the string from the serialized stream writer.Position = 0; StreamReader sr = new StreamReader(writer,System.Text.Encoding.ASCII); ret = sr.ReadToEnd(); return ret; }
MS Logging and Instrumentation Block
Error: The type initializer for "Microsoft.Practices.EnterpriseLibrary.Data.Instrumentation.DataConnectionFailedEvent" threw an exception.
Repeat the following for all the code blocks you are using:
C:\WINNT\Microsoft.NET\Framework\v1.1.4322\InstallUtil.exe <destinationfolder>\Microsoft.Practices.EnterpriseLibrary.Common.dll
Intermittent Web Services Error I have a proxy class that performs a large number of calls on a web service.
It fails intermittently with the following error:
System.Net.WebException: The request failed with HTTP status 401:
Unauthorized. at System.Web.Services.Protocols.SoapHttpClientProtocol.
ReadResponse(SoapClientMessage message, WebResponse response,
Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke
(String methodName, Object[] parameters)
To fix this, you should disable the Keep Alive feature on IIS and the proxy class.
Disable Keep Alive in IIS To disable go to the Web site tab of the Web site properties window and uncheck the Keep Alive options.
Disable Keep Alive in Proxy You need to override the default handling of WebRequest as shown below:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest =
(System.Net.HttpWebRequest) base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}
More Information on Keep Alive Keep alive keeps the connection open across multiple requests.
To find out more, see:
https://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/59e9c2d2-b772-4c43-82f0-e669427eeb89.mspx and
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemnethttpwebrequestclasskeepalivetopic.asp
Web Service Inheritance ErrorWe have a bunch of web services that are derived from a base web service class.When running one of the derived web services, I got the following error:“Server did not recognize the value of HTTP Header SOAPAction:”The error was caused by not providing an explicit namespace for the derived web service class. The following attribute fixed the error:[WebService(Namespace="someuri")]Class DerivedWebService : BaseWebService{