Dev Team Assemble

Evil beware!
Add to Technorati Favorites

Archive

Category: .Net Framework

Heres a neat little snippit that comes in handy for running commands against the operating system.

Sourced directly from here: http://stackoverflow.com/questions/691716/running-cmd-commands-via-net ...but I like having the code here as well.

 
// Kills a process
<span> </span> private static void ExecuteCommand(string command)
{
try
{
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/c " as the parameters. &gt; tell the command to execute the command that follows
System.Diagnostics.ProcessStartInfo procStartUpInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartUpInfo.RedirectStandardOutput = true;
procStartUpInfo.UseShellExecute = false;
// Do not create a window.
procStartUpInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartUpInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
Console.WriteLine(objException);
}
}
 

Technorati Tags: , , , ,

Here is some useful information that I always seem to forget when developing windows services.

  • To install/uninstall manually, which i find helpful to do from the bin folder of your project use the following commands:
    • INSTALL: %windir%\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe [the name of the executable]
    • UNINSTALL: %windir%\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe -u [the name of the executable]
  • To Debug a windows service add the following code to your Main method

    static void Main(string[] args)
    {
    #if DEBUG
    System.Diagnostics.Debugger.Break();
    #endif

    ServiceBase.Run(new Service());

    }

  • To create an installation package for a service: ....I will come back to that - no time to put it together today :)

Technorati Tags: , , ,

I have been working with xml serialization over the last week or so and ran into a strange issue today. It only came to light when I decided to implement IXmlSerializable and write my own methods for reading and writing the xml. I posted recently about using he XmlRootAttribute as a fix for the xmlns='' > was not expected error I was seeing. This all worked fine and dandy until I really started to utilize that method over and over again in my code. I found the performance of this to be horrible...so horrible in fact it was taking 2-3 minutes to deserialize a moderately complex 1MB xml file. After doing some digging (on "The Google") I discovered that microsoft decided to only implement caching on the Xml serializer when you use one of the two "more common" constructors (see documentation). Of course it would seem the one I need would not be one of them.

I was thinking of somehow adding the XmlSerializers for each type/root pair that I was using to the application level cache or something like that but thought that might bring with it its own set of challenges. I found a great article here on stack overflow that shows a possible workaround for the problem using a static class to act as a cache or you.

Please note this code is taken directly from the article above:


public static class XmlSerializerCache
{
private static readonly Dictionary cache =
new Dictionary();

public static XmlSerializer Create(Type type, XmlRootAttribute root)
{
var key = String.Format( CultureInfo.InvariantCulture, "{0}:{1}", type, root.ElementName);

if (!cache.ContainsKey(key))
{
cache.Add(key, new XmlSerializer(type, root));
}

return cache[key];
}
}

Here is how you use it to create an XmlSerializer object:


var xmlRootAttribute = new XmlRootAttribute("ExampleElement");
var serializer = XmlSerializerCache.Create(target.GetType(), xmlRootAttribute);

After implementing that I was still experiencing the 2-3 minute deserialization one the first call but all subsequent calls to that code with similar xml took only 2 seconds.

NOTE:
Seems microsoft is in the habit of only half implementing caching in their code. This problem is almost identical to the problems with the CrossListQueryCache object in SharePoint....where they again only implemented caching for two of the four available method signatures. Here is an interesting article I found in the nether-regions of cyberspace where microsoft state this half implementation is by design...

Technorati Tags: , , , , , , ,

I had what turns out to be a fairly common error the other day when trying to deserialize an xml file in one of my applications.  Here is the code I was running:


XmlSerializer ser = new XmlSerializer(typeof(MyObject));
XmlReader xRdr = XmlReader.Create(new StringReader(xmlData));
MyObject tvd = (MyObject)ser.Deserialize(xRdr);

As it turns out this was causing the error: xmlns=''> was not expected during deserialization. Alot of the resources online (including the msdn article here) were pointing me to the namespaces not being the same on the serializer and document. I am not sure why it wasn't working for me because I was playing around with the namespaces but couldn't seem to figure out how to get that working. Maybe because I was only serializing a fragment of a document I'm not sure. Anyway it turns out that specifying the XmlRootAttribute in the XmlSerializer constructor fixed the problem for me. This Stack Overflow article really helped Here is the snippet of code that I am using now:


XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = elementName;
xRoot.IsNullable = true;

XmlSerializer ser = new XmlSerializer(typeof(MyObject), xRoot);
XmlReader xRdr = XmlReader.Create(new StringReader(xmlData));
MyObject tvd = (MyObject)ser.Deserialize(xRdr);

Hope this helps

Technorati Tags: , , , , ,

I came across this problem recently. Its a little strange and only happened once I changed my base webpart class to inherit from Microsoft.SharePoint.WebPartPages.WebPart. There seems to be two fixes for this problem that I implemented:

  • remove the XMlNamespace from class declaration
  • Use a .dwp file instead of a .webpart file in your feature folder

Technorati Tags: , ,

For the last little bit I have been working on learning how to package up all site infrastructure into a single feature.  All of this is pretty straight forward and I didn't really have any issues.....UNTIL  I tried to get lookup columns working.

Using CAML

I did some reading on the subject and apparently you can do all of this using CAML alone.  I came across a post from Josh Gaffery supporting this claim, but I simply could not get this working...so i gave up after spinning my wheels on it for longer than I wanted to.  Josh's approach is to use the list URL as opposed to the GUID that links the column to the source list and he has put up an update explaining it further.  Nonetheless....didn't work for me.

Using Feature Receiver

I knew that at this point I would have to take the feature reciever approach and modify the fields in place or create them.  I found two sources that both take different approachs to this problem.

  • Chris O'Brien has put together the a project on CodePlex that will create the lookup columns at activation time.  This actully sounds like a pretty good approach but unfortunately it didn't work for me.  I dont know if there is something wrong with my environment but I encountered a few errors doing this...things like the fields not rendering on the page layouts and getting the "The local device name is already in use. (Exception from HRESULT: 0x80070055)" error.
  • Waldek Mastykarz has a great post on creating the columns via code here.

Basically I took a hybrid approach to doing this by mixing the two approaches mentioned above.  I created a custom XML file that I deploy into the layouts directory and then use a feature reciever to read the xml content and create lookup columns based on this.  I also added a deactiving event to remove the fields when the feature is deactivated.  Heres the feature reciever code:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            using (SPSite site = properties.Feature.Parent as SPSite)
            {
                string contentTypes = null;
                string listName = null;
                string fieldName = null;
                string groupName = null;
                string staticName = null;
                string lookupFieldName = "Title";
                bool mult = false;
                bool required = false;
                string filePath = properties.Feature.Properties[
                   "ColumnDefinitionPath"].Value;
 
                XmlTextReader xReader = new XmlTextReader(
                  HttpContext.Current.Server.MapPath(@"~\_layouts\" + filePath));
                while (xReader.Read())
                {
                    if (xReader.LocalName == "Field")
                    {
                        #region Get values from attributes
                        if (xReader.MoveToAttribute("List"))
                        {
                            listName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Name"))
                        {
                            fieldName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("StaticName"))
                        {
                            staticName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Group"))
                        {
                            groupName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("LookUpField"))
                        {
                            lookupFieldName = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("ExistInContentTypes"))
                        {
                            contentTypes = xReader.Value;
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Mult"))
                        {
                            bool.TryParse(xReader.Value, out mult);
                            xReader.MoveToElement();
                        }
                        if (xReader.MoveToAttribute("Required"))
                        {
                            bool.TryParse(xReader.Value, out required);
                            xReader.MoveToElement();
                        }
 
                        #endregion
 
                        SPFieldLookup lookup = CreateLookupField(
                          fieldName, groupName, required, mult, site.RootWeb,
                          site.RootWeb.Lists[listName], lookupFieldName, staticName);
                        if (contentTypes != null)
                            foreach (string s in contentTypes.Split(','))
                            {
                                LinkFieldToContentType(s.Trim(), (SPField)lookup);
                            }
                    }
                }
 
                xReader.Close();
 
            }
        }
 
        public static SPFieldLookup CreateLookupField(
          string fieldName, string group, bool required, bool allowMultipleValues,
          SPWeb w, SPList lookupList, string lookupField, string staticName)
        {
            w.Fields.AddLookup(fieldName, lookupList.ID,
               lookupList.ParentWeb.ID, required);
            SPFieldLookup lookup = (SPFieldLookup)w.Fields[fieldName];
            lookup.AllowMultipleValues = allowMultipleValues;
            lookup.LookupField = lookupField;
            lookup.StaticName = staticName;
            lookup.Group = group;
            lookup.Update(true);
            return lookup;
        }
 
        public static void LinkFieldToContentType(string contentType, SPField field)
        {
            using (SPSite site = SPContext.Current.Web.Site as SPSite)
            {
                SPContentType ct = site.RootWeb.ContentTypes[contentType];
                ct.FieldLinks.Add(new SPFieldLink(field));
                ct.Update(true); // will update children
            }
        }

As you can read from the above code the xml file would need to have a node like below for each lookup column:

 
<Field
         Type="Lookup"
         List="Access Type"
         Name="AccessTypeColumn"
         StaticName="Access_x0020_Type"
         Group="Infrastructure"
         ExistInContentTypes="THIS IS A COMMA DELIMITED LIST OF CONTENT NAMES"
         LookUpField="Title"
         Mult="TRUE"
         Required="FALSE"
        />
 

The Final Project

So here are all the pieces of my infrastructure project. Notice the placement of the lookupfields xml file...this is because the layouts directory is setup as a virtual directory for every sharepoint site and we can read files from there without a permissions problem.

12/TEMPLATES/FEATURES/myfeature/lists.xml this contains the source lists for the lookup fields
12/TEMPLATES/FEATURES/myfeature/contenttypes.xml this contains the content type definitions MINUS the lookup fields
12/TEMPLATES/FEATURES/myfeature/sitecolumns.xml this contains all the other fields included in the content types
12/TEMPLATES/FEATURES/myfeature/feature.xml the feature def
12/TEMPLATES/LAYOUTS/myfeature/lookupfields.xml this contains all the lookup fields that need to be provisioned

Hopefully this helps anyone who's been having problems getting this going. And a big thanks to Waldek, Chris and Josh for their posts.

Technorati Tags: , , , ,

Great post here with a fix/workaround. Essentially when you go to look in the windows .net framework directory that program is not there. In order to run this utility program you will need to use the Visual Studio command prompt that is in the Programs/Visual Studio menu.

Technorati Tags: , , , ,

I got the following error the other day (it has been shortened...):

"the web part you attempted to add no longer exists in the closed web parts gallery."

This was a pretty disturbing error...there was no real apparent cause for this problem...nothing in the logs. After messing about with it for a while I figured out that it was a dll version in the GAC that was causing the problem. On my dev box I had an updated version but the version in our prod envs is different.

It would be nice if the server was a little more helpful with its error messages....HTH if you come across it

Technorati Tags: , , , ,

From November 2008:

Whew...its been a long week and its only Thursday. This years conference was much the same as last years with the exception of being held in various portions of the Mandalay Bay convention center as opposed to on one floor. This made for lots and lots and lots and lots of walking. But I'm still young (yes i am) so it makes for good excercise to walk off all the food they shovel in your mouth.

Most of the sessions I attended were really good with the exception of a couple. I wouldn't blame the speakers because these problems were mostly due to technical issues like the computers not working, the projectors broken or feedback in the presenters microphone sort of thing. All in all there were some great things presented this week.

Some of the sessions that really stuck out were:

Kimberly Tripp - Index Internals and Usage
This was a great session that talked about thins like SQL Server Statistics, Query Optimization, Types of indexes, diminishing returns on performance, etc. Of all the session I think this one stood out the most and because it is probably the most relevant for me right now being one of the "SQL Server DBA" for my company (Christie Digital). I say it that way because its a committee based DBA :)

Rick Strahl - Using WCF for JSON and REST Services with ASP.Net

Great session....last one of the conference for me so it really sticks out but essentially this covers the next gen replacement for ASMX or first gen webservices in the .NET Framework.

John Papa - Practical Strategies with the Entity Framework

For me this was an introduction to the Entity Framework that was released in VS 2008 SP1. John did a great job of quickly introducing the technology and getting on to the meat and potatoes of what we were there to discuss. There was a good discussion on how to use the IDE to build the data mappings and what happens after you make changes to the backend server, which coinceidently can be any data source...not just SQL as Linq to SQL supports.

Things I would change...(and only because its my blog and I can say whatever I want!!!)

...the time between sessions was ridiculous...one hour or in some cases and hour and a half is just way too long. They could have added an extra session or two to the day. I realize they want you in the expo hall but they could have extended the day to facilitate that or leave it open all day and then some people may skip a couple of sessions here and there to go and see what the vendors are offering. this was my gripe last year and its my gripe this year. Its probably going to be the thing that keeps me from going to this in the future.

...provide video or podcasts of the sessions so we can take in the whole conference...even the sessions we didn't get to go to. I see there point about this being intellectual property and the speakers are consultants and this is their livelyhood but I mean if they are willing to teach this at a conference...and we pay to see it...shouldn't we be entitled to review this information after the fact? Maybe they will supply it on their site (i heard they were recording the sessions this year).

...ease up on the food. Damn, there was too much...I ate too much...I felt stuffed the whole time...I guess this is really my fault! Okay dont change that :)

Technorati Tags: , , , , , ,

Heres a simple way for you to view your GAC in its naked state, go to the following registry location:

HKLM\Software\Microsoft\Fusion, once there create a DWORD value named "DisableCacheViewer" and set it to value 1.

Easy!

Technorati Tags: , ,