Archive

Archive for the ‘ASP.NET’ Category

Creating a DNS Entry in Windows 20003 Std Edition with c# .NET

January 23rd, 2009 Michael Bell No comments

One of the websites I did in the past required me to be able to register a domain, create the site in IIS, add the DNS entries, and add email entries into HMail server. Here is the DNS server half of it. Of course you have to have permissions, but this is the method I used to get from A to B entering a new domain name into the DNS Server in Windows 2003 Standard Edition. You can tell by my exception block that this piece of code was executed from an ASP.NET Web Application:

///


/// Created an entry in DNS Server on a Windows 2003 Server
///

/// Domain name and TLD Extension /// IP Address the site belongs to in IIS /// IP Address of the DNS Server itself /// Email of the administrator for this domain public void new_Zone(string Domain, string AssignToIpAddr, string PrimaryServerIP, string AdminEmailName)
{
Domain = Domain.ToLower();
try
{
string[] ipArray;
ipArray = new string[1] { AssignToIpAddr };

//Create Foward Lookup Zone.
string sServerPath = “\\\\WINDOWS\\ROOT\\MicrosoftDNS”;
ManagementScope oScope = new ManagementScope(sServerPath);
oScope.Connect();
ManagementPath Path = new ManagementPath(”MicrosoftDNS_Zone”);
ManagementClass DnsZoneClass = new ManagementClass(oScope, Path, null);
ManagementBaseObject InputParams = DnsZoneClass.GetMethodParameters(”CreateZone”);

InputParams["ZoneName"] = Domain;
InputParams["ZoneType"] = 0;
InputParams["AdminEmailName"] = AdminEmailName;
InputParams["IpAddr"] = ipArray;
ManagementBaseObject OutParams = DnsZoneClass.InvokeMethod(”CreateZone”, InputParams, null);

#region A Records
ManagementPath newPath = new ManagementPath(”MicrosoftDNS_ATYPE”);
ManagementClass ARecordClass = new ManagementClass(oScope, newPath, null);
ManagementBaseObject ARecord = ARecordClass.GetMethodParameters(”CreateInstanceFromPropertyData”);ARecord["DnsServerName"] = “WINDOWS”;

ARecord["ContainerName"] = Domain;
ARecord["OwnerName"] = Domain;
ARecord["IPAddress"] = ipArray[0];

OutParams = ARecordClass.InvokeMethod(”CreateInstanceFromPropertyData”, ARecord, null);

ManagementClass dnsRRClass = new ManagementClass(@”\\” + System.Environment.MachineName + @”\root\MicrosoftDNS”, “MicrosoftDNS_ResourceRecord”, null);
ManagementBaseObject inParams = dnsRRClass.GetMethodParameters(”CreateInstanceFromTextRepresentation”);

inParams["DnsServerName"] = “.”;
inParams["ContainerName"] = Domain;
inParams["TextRepresentation"] = “www.” + Domain + ” IN A ” + ipArray[0];
OutParams = dnsRRClass.InvokeMethod(”CreateInstanceFromTextRepresentation”, inParams, null);

dnsRRClass = new ManagementClass(@”\\” + System.Environment.MachineName + @”\root\MicrosoftDNS”, “MicrosoftDNS_ResourceRecord”, null);
inParams = dnsRRClass.GetMethodParameters(”CreateInstanceFromTextRepresentation”);

inParams["DnsServerName"] = “.”;
inParams["ContainerName"] = Domain;
inParams["TextRepresentation"] = “mail.” + Domain + ” IN A ” + ipArray[0];
OutParams = dnsRRClass.InvokeMethod(”CreateInstanceFromTextRepresentation”, inParams, null);

#endregion
}
catch (Exception ex)
{
//throw;
HttpContext.Current.Response.Write(ex.Message + “
”);
HttpContext.Current.Response.Write(ex.StackTrace);
HttpContext.Current.Response.Write(ex.ToString());
HttpContext.Current.Response.End();
}
}

Categories: ASP.NET, DNS, IIS, c# Tags:

Automating SharePoint web.config Changes

January 20th, 2009 Michael Bell No comments

Here is my take on automating web.config changes in SharePoint 2007. In this example I make some changes so that I see detailed errors and stack traces on exceptions that are thrown within SharePoint. A few things I learned while playing around with this the first few times:

  • If you have mods going in in several places, or have lots of mods, complete them all and then do your Update() and ApplyWebConfigModifications(). If you do several saves, you will run into some strange looking problems during your deploys. It acts like there’s another package that didn’t get finished deploying and stop you.
  • Be mindful of the “Owner” property. It keeps track of who owns what modifications. It’s easy to wind up with orphans while you’re just learning how to do this, and you can hack up the web.config pretty good like that. If you end up fouling up your config settings like I did (Hey, I’m not an XPath guy!), check out Vincent Rothwell’s post on cleaning it up.
  • Brush up on XPath before you start executing this stuff.

Keep in mind that in this example I put the Update and Apply in the end just for the purpose of providing a complete example. In a real world scenario, you could use this method while you’re adding other modifications, but you wouldn’t want to save those mods until they are all added to the collection. 1 save per activation.

internal static void setErrorDetailSettings(SPWebApplication WebApp, string Owner, bool ShowErrors)
{

    SPWebApplication WebApp = siteCollection.WebApplication;
    SPServiceCollection services = WebApp.Farm.Services;
    SPWebApplicationCollection WebApps = services.GetValue<SPWebService>().WebApplications;

    string callStackValue = (ShowErrors) ? “true” : “false”;
    string customErroresValue = (ShowErrors) ? “Off” : “On”;

    SPWebConfigModification stackTraceModification =
        new SPWebConfigModification(“CallStack”, “configuration/SharePoint/SafeMode”);
    stackTraceModification.Value = callStackValue;
    stackTraceModification.Sequence = 1;
    stackTraceModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute;
    WebApp.WebConfigModifications.Add(stackTraceModification);

    SPWebConfigModification customErrorsModification =
        new SPWebConfigModification(“mode”, “configuration/system.web/customErrors”);
    customErrorsModification.Value = customErroresValue;
    customErrorsModification.Sequence = 1;
    customErrorsModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute;
    WebApp.WebConfigModifications.Add(customErrorsModification);

    WebApp.Update();
    WebApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
}

Categories: ASP.NET, MOSS, SharePoint 2007, c# Tags:

“Column is constrained to be unique. Value is already present.” Error with in-memory table row inserts

November 30th, 2006 Michael Bell No comments

With my in-memory log-hit table I talked about in my last entry, I started getting these errors a few times a day, and it was enough to bomb the whole app:
Column ‘blahblah’ is constrained to be unique.  Value ‘-4862′ is already present.
Column ‘blahblah’ is constrained to be unique.  Value ‘-4847′ is already present.
Column ‘blahblah’ is constrained to be unique.  Value ‘-4768′ is already present.

Let me show you how the ‘blahblah’ column is built in the table construction:
DataColumn dc;

dc = new DataColumn(“HitID”, typeof(Int32));
dc.Unique = true;
dc.AutoIncrement = true;
dc.AutoIncrementSeed = -1;
dc.AutoIncrementStep = -1;
_MyTable.Columns.Add(dc);

So how in the world is this happening? Let me show the piece of code that was throwing the exception:
DataRow row = MemoryTables.HitList.NewRow();
row["FileID"] = Convert.ToInt32(context.Request.QueryString["fi"]);
row["FileName"] = fi.Name;
row["Username"] = _Username;
row["MemberID"] = _MemberID;
row["Success"] = true;
row["Bytes"] = fi.Length;
MemoryTables.HitList.Rows.Add(row);

Fairly straight forward.. right? With each hit to an image, this thing fires and inserts a new row into the in-memory table. About 20 rows get inserted a second. After much trial and error, I completely eliminated this problem by re-arranging a few lines of code. The new code reads:
DataRow row = MemoryTables.HitList.NewRow();
MemoryTables.HitList.Rows.Add(row);
row["FileID"] = Convert.ToInt32(context.Request.QueryString["fi"]);
row["FileName"] = fi.Name;
row["Username"] = _Username;
row["MemberID"] = _MemberID;
row["Success"] = true;
row["Bytes"] = fi.Length;

By creating a new row and adding it to the table before I populate it with any values, I eliminate my problem. I’d love to hear an explanation if anyone has one…

Categories: ASP.NET, c# Tags:

Efficient Hit Logging with ASP.NET 2.0 & Microsoft SQL Server

November 7th, 2006 Michael Bell No comments

I’ve been running image hosting sites for a couple of years. Through my trials I discovered a few things. Running the web server AND the sql server off the same box when you are getting a couple of million image hits a day can be trying on your system. The first version of my image hosting site wrote logs as they came in. 1 image hit actually equalled 3 queries to the DB. That was due to a lack of experience in both architecture and ASP.NET.

In July I decided to rewrite my ASP.NET 1.1 in 2.0. I have plenty of ram in my box, and i knew I wanted to do less queries to my database. What I wound up doing was an in-memory datatable that gets a record for each hit. I used the TableNewRow datatable event to check the record count with each insert. Probaboy not the best method… but I went with it. A more preferable way to do it would be to use a Timer object and firing on the Tick event. In any case, once I reach 10k records, I do a “dump” to the database of the in-memory stuff, and then clean my in-memory table.

As for the “dump”… well… the redesign could not have come at a better time. I was able to utilize the new .NET 2.0 SqlBulkCopy class. What this amounted to was a 4 second query every 10 minutes. Compare that to the alternative of doing several inserts a second… and you can start to see the advantage of in the in-memory/SqlBulkCopy dump technique.

After I released my new version of my image hosting site, I found out REAL fast that there were some problems related to sharing in-memory datatables that are accessed (read, write) constantly (writes 15-20 times a second).

It took me quite a bit of trial and error to figure out how to get it stablized. The server I was working on had dual xeon processors with hyper-threading enabled. What I found was that when this combination was being used, and I was logging hits to an in-memory datatable 15-20 times a second, different threads were trying to log to this table at the same time, causing all hell to break loose.

The fix – briefly lock the table during writes:
lock (MemoryTables.HitList)
{
    MemoryTables.HitList.Rows.Add(row);
}

The dump/rebuild procedure also requires a lock, but it’s very brief:
using (SqlConnection sourceConnection = new SqlConnection(_ConnectionString))
            {
                sourceConnection.Open();

                using (SqlBulkCopy copy = new SqlBulkCopy(sourceConnection))
                {
                    #region Dump and clear hit list
                    copy.DestinationTableName = “FileHits”;
                    lock (_HitList) // Place a lock on the table so incoming hits won’t interupt our dump or our clear
                    {
                        copy.WriteToServer(_HitList);

                        try
                        {
                            if (!(EventLog.SourceExists(SourceName)))
                            {
                                EventLog.CreateEventSource(SourceName, LogName);
                            }

                            // Insert into Event Log so we know logging is taking place as expected;
                            EventLog MyLog = new EventLog();
                            MyLog.Source = SourceName;
                            MyLog.WriteEntry(“Hit data has been dumped. HitList Records: ” + _HitList.Rows.Count, EventLogEntryType.Information);
                        }
                        catch (Exception ex)
                        {
                            throw;
                        }
                        finally
                        {
                            _HitList.Clear();
                        }
                    }
                    #endregion
                }
            }

I half-expected the locking to cause a delay problem in my logging abilities, but I’ve noticed no bottlenecks at all, and this method has been operating trouble free for about a month now.

Categories: ASP.NET, Whatever, c# Tags: