Our Services
Recent Posts
02/02/2010 |Karl Hering
ASP.NET 2.0 brought a lot to the table with the Membership and Profiles API, and when coupled with some fine techniques provided by jquery some very sleek-looking login functionality can be provided to your users. We just finished a nifty presentation model when working with login functionality for a new non-for-profit site; SpaceForGood.  This article will attempt to highlight the core settings used to put together the Profiles web services with your site, as well as depict an example of the script used to invoke it client-side. First of all I want to bring out that this article is going to assume that you are already familiar with the Profile API of ASP.NET 2.0. You should already know how to make a connection string in your web.config file, and at least a brief understanding of membership, users and the concept of each user having their own profile. Also, you should at least be somewhat familiar with ASP.NET AJAX and how to put the dll's in your bin folder and update your web.config. Even if you're not fully up on these concepts just yet, you can still benefit from seeing how easy it is, and maybe that will inspire you to get started. Exposing Your Profile in the Web.config In order to access the profile service vis-a-vis AJAX or jquery, you will have to enable a few properties in your web.config first: <profile>      <providers>        <clear/>        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="MyConnectionString" applicationName="/" />              </providers>      <properties>        <add name="FirstName" type="System.String"/>        <add name="LastName" type="System.String"/>        <add name="JobTitle" type="System.String"/>        <add name="Email1" type="System.String"/>        <add name="Email2" type="System.String"/>        <add name="Email3" type="System.String"/>        <add name="HomePhone" type="System.String"/>        <add name="WorkPhone" type="System.String"/>        <add name="MobilePhone" type="System.String"/>        <group name="Organization">          <add name="Keys"/>        </group>      </properties>    </profile>     ... <system.web.extensions>    <scripting>      <webServices>        <authenticationService enabled="true" />        <roleService enabled="true"/>        <profileService enabled="true" readAccessProperties="FirstName, LastName, Email1, Email2, Email3"/>              </webServices>    </scripting>  </system.web.extensions> Once you have enabled the service in your web.config file, you can interact with these services using codes somewhere along the lines of... // login function doLogin() {     $("#loginMessage").html("");     var userNameValue = $("#userNameInput").val();     var passwordValue = $("#passwordInput").val();     var rememberMeValue = $("#rememberMeInput").val();     var persistLogin = (rememberMeValue == "persist");     // call the authetication service to authenticate the credentials entered by the user.     Sys.Services.AuthenticationService.login(userNameValue, passwordValue,         persistLogin, null, null, OnLoginCompleted, OnAuthenticationFailed, "User Context"); } // login completed function OnLoginCompleted(validCredentials, userContext, methodName) {     if (validCredentials) {         $("#username").attr("value", "");       // clear login entry         $("#password").attr("value", "");       // clear password entry         LoadRoles();     }     else {         $("#loginMessage").html("Invalid user credentials");     } } // logout completed function OnLogoutCompleted(result) {     $("#username").attr("value", "");   // clear login entry     $("#password").attr("value", "");   // clear password entry     $("#userWelcomeDisplay").html("Hello There!");   // obviously you can do something more elaborate } // authentication failed function OnAuthenticationFailed(error, userContext, methodName) {     alert("Authentication service failed with message: " + error.get_message()); } // loads the profile of the current authenticated user function LoadProfile() {     var loggedIn = Sys.Services.AuthenticationService.get_isLoggedIn();     if (loggedIn) {         Sys.Services.ProfileService.load(null, OnLoadProfileCompleted, OnLoadProfileFailed, "User Context");     }     else {         OnLogoutCompleted(null);     } } // reads the profile information and displays it function OnLoadProfileCompleted(numProperties, userContext, methodName) {     // todo: display some user information } // callback function called if the profile load or save operations failed. function OnLoadProfileFailed(error, userContext, methodName) {     alert("Profile service failed with message: " + error.get_message()); } 
01/11/2010 |Karl Hering
If you are recieving the generic error "Sequence contains no elements." it is because LINQ creates an InvalidOperationException when you are looking for a record that doesn't exist. Your code may look something like... return this.DataContext.MyRecords.Single([expression]);return (from record in DataContext.MyRecords where [someCondition] select record).Single(); In place of of Single, you can alternatively use SingleOrDefault, which will return null if the object doesn't exist. return this.DataContext.MyRecords.SingleOrDefault([expression]);return (from record in DataContext.MyRecords where [someCondition] select record).SingleOrDefault();
12/14/2009 |Karl Hering
I'm continuing my previous post to include a few more tips to help you...mainly concerned with execution performance. I know that with my projects, time is always the issue. What may seem like a small 5-10 min transfer operation becomes large when coupled with 45 other processes that must run in the morning as part of a data warehouse load. With SQL Server 2008, I recently read that SSIS 2008 has further enhanced the internal dataflow pipeline engine to provide even better performance, you might have heard the news that SSIS 2008 has set an ETL World record of uploading 1TB of data in less than half an hour. Pulling High Volumes of Data As part of a recent project, we had to pull data from a source table which had ~ 4 million records to a new target table. Initially when the SSIS package started, everything looked fine, data was being transferred as expected but gradually the performance degraded and the data transfer rate went down dramatically. During analysis we found that the target table had a primary clustered key and two non-clustered keys. Because of the high volume of data inserts into the target table these indexes got fragmented heavily up to 85%-90%. We used the online index rebuilding feature to rebuild/defrag the indexes, but again the fragmentation level was back to 90% after every 15-20 minutes during the load. This whole process of data transfer and parallel online index rebuilds took almost 12-13 hours which was much more than our expected time for data transfer. Then we came with an approach to make the target table a heap by dropping all the indexes on the target table in the beginning, transfer the data to the heap and on data transfer completion, recreate indexes on the target table. With this approach, the whole process (by dropping indexes, transferring data and recreating indexes) took just 3-4 hours which was what we were expecting. Rows Per Batch Settings Rows per batch – The default value for this setting is -1 which specifies all incoming rows will be treated as a single batch. You can change this default behavior and break all incoming rows into multiple batches. The allowed value is only positive integer which specifies the maximum number of rows in a batch. Maximum insert commit size – The default value for this setting is '2147483647' (largest value for 4 byte integer type) which specifies all incoming rows will be committed once on successful completion. You can specify a positive value for this setting to indicate that commit will be done for those number of records. You might be wondering, changing the default value for this setting will put overhead on the dataflow engine to commit several times. Yes that is true, but at the same time it will release the pressure on the transaction log and tempdb to grow tremendously specifically during high volume data transfers. The above two settings are very important to understand to improve the performance of tempdb and the transaction log. For example if you leave 'Max insert commit size' to its default, the transaction log and tempdb will keep on growing during the extraction process and if you are transferring a high volume of data the tempdb will soon run out of memory as a result of this your extraction will fail. So it is recommended to set these values to an optimum value based on your environment. Note: The above recommendations have been done on the basis of experience gained working with DTS and SSIS for the last couple of years. But as noted before there are other factors which impact the performance, one of the them is infrastructure and network. So you should do thorough testing before putting these changes into your production environment. Avoid SELECT * I know this recommendation has been around forever for most DBAs and developers, but in SSIS there is an additional important consideration to avoid using SELECT *. The Data Flow Task (DFT) of SSIS uses a buffer (a chunk of memory) oriented architecture for data transfer and transformation. When data travels from the source to the destination, the data first comes into the buffer, required transformations are done in the buffer itself and then written to the destination. The size of the buffer is dependant on several factors, one of them is the estimated row size. The estimated row size is determined by summing the maximum size of all the columns in the row. So the more columns in a row means less number of rows in a buffer and with more buffer requirements the result is performance degradation. Hence it is recommended to select only those columns which are required at destination. Even if you need all the columns from the source, you should use the column name specifically in the SELECT statement otherwise it takes another round for the source to gather meta-data about the columns when you are using SELECT *. OLEDB Destination Settings There are couple of settings with OLEDB destination which can impact the performance of data transfer. Data Access Mode – This setting provides the 'fast load' option which internally uses a BULK INSERT statement for uploading data into the destination table instead of a simple INSERT statement (for each single row) as in the case for other options. So unless you have a reason for changing it, don't change this default value of fast load. If you select the 'fast load' option, there are also a couple of other settings which you can use as discussed below. Keep Identity – By default this setting is unchecked which means the destination table (if it has an identity column) will create identity values on its own. If you check this setting, the dataflow engine will ensure that the source identity values are preserved and same value is inserted into the destination table. Keep Nulls – Again by default this setting is unchecked which means default value will be inserted (if the default constraint is defined on the target column) during insert into the destination table if NULL value is coming from the source for that particular column. If you check this option then default constraint on the destination table's column will be ignored and preserved NULL of the source column will be inserted into the destination. Table Lock – By default this setting is checked and the recommendation is to let it be checked unless the same table is being used by some other process at same time. It specifies a table lock will be acquired on the destination table instead of acquiring multiple row level locks, which could turn into lock escalation problems. Check Constraints – Again by default this setting is checked and recommendation is to un-check it if you are sure that the incoming data is not going to violate constraints of the destination table. This setting specifies that the dataflow pipeline engine will validate the incoming data against the constraints of target table. If you un-check this option it will improve the performance of the data load.
11/03/2009 |Karl Hering
I've been employing SQL Server Integration Services for some years now and find it to be quite an improvement over its predecessor Data Transformation Services. Apart from being an ETL product, it also provides different built-in tasks to manage a SQL Server instance. SSIS is not an enhancement to DTS but rather a new product which has been written from scratch to provide high performance and parallelism and as a result of this it overcomes several limitations of DTS. Not to mention the fact that versions of each package are easilty stored and maintained using TFS, and so plays well with other Visual Studio design elements by your support team. The best part of SSIS is that it is a component of SQL server.  It comes free with the SQL Server installation and you don't need a separate license for it. Because of this, along with hardcore BI developers, database developers and database administrators are also using  it to transfer and transform data. Here are some tips when employing SSIS that I've come across over the past couple years... Avoid asynchronous transformation wherever possible Before I talk about different kinds of transformations and its impact on performance, let me briefly talk about of how SSIS works internally. The SSIS runtime engine executes the package.  It executes every task other than data flow task in the defined sequence.  Whenever the SSIS runtime engine encounters a data flow task, it hands over the execution of the data flow task to data flow pipeline engine. The data flow pipeline engine breaks the execution of a data flow task into one more execution tree(s) and may execute two or more execution trees in parallel to achieve high performance. Now if you are wondering what an execution tree is, then here is the answer. An execution tree, as name implies, has a similar structure as a tree.  It starts at a source or an asynchronous transformation and ends at destination or first asynchronous transformation in the hierarchy. Each execution tree has a set of allocated buffer and scope of these buffers are associated the execution tree. Also each execution tree is allocated an OS thread (worker-thread) and unlike buffers this thread may be shared by any other execution tree, in other words an OS thread might execute one or more execution trees. In SSIS 2008, the process of breaking data flow task into an execution tree has been enhanced to create an execution path and sub-path so that your package can take advantage of high-end multi-processor systems. Synchronous transformations get a record, process it and pass it to the other transformation or destination in the sequence. The processing of a record is not dependent on the other incoming rows. Because synchronous transformations output the same number of records as the input, it does not require new buffers (processing is the done in the same incoming buffers i.e. in the same allocated memory) to be created and because of this it is normally faster. For example, in the Derived column transformation, it adds a new column in the each incoming row, but it does not add any additional records to the output. Unlike synchronous transformations, the asynchronous transformation might output a different number of records than the input requiring new buffers to be created. Because an output is dependent on one or more records it is called a blocking transformation.  Depending on the types of blocking it can either be partially blocking or a fully blocking transformation.  For example, the Sort Transformation is a fully blocking transformation as it requires all the incoming rows to arrive before processing. As discussed above, the asynchronous transformation requires addition buffers for its output and does not utilize the incoming input buffers.  It also waits for all incoming rows to arrive for processing, that's the reason the asynchronous transformation performs slower and must be avoided wherever possible. For example, instead of using Sort Transformation you can get sorted results from the source itself by using ORDER BY clause. DefaultBufferMaxSize and DefaultBufferMaxRows The number of buffer created is dependent on how many rows fit into a buffer and how many rows fit into a buffer dependent on few other factors. The first consideration is the estimated row size, which is the sum of the maximum sizes of all the columns from the incoming records. The second consideration is the DefaultBufferMaxSize property of the data flow task.  This property specifies the default maximum size of a buffer. The default value is 10 MB and its upper and lower boundaries are constrained by two internal properties of SSIS which are MaxBufferSize (100MB) and MinBufferSize (64 KB). It means the size of a buffer can be as small as 64 KB and as large as 100 MB. The third factor is, DefaultBufferMaxRows which is again a property of data flow task which specifies the default number of rows in a buffer.  Its default value is 10000. Although SSIS does a good job in tuning for these properties in order to create a optimum number of buffers, if the size exceeds the DefaultBufferMaxSize then it reduces the rows in the buffer. For better buffer performance you can do two things.  First you can remove unwanted columns from the source and set data type in each column appropriately, especially if your source is flat file.  This will enable you to accommodate as many rows as possible in the buffer. Second, if your system has sufficient memory available, you can tune these properties to have a small number of large buffers, which could improve performance. Beware if you change the values of these properties to a point where page spooling begins, it adversely impacts performance. BufferTempStoragePath and BLOBTempStoragePath If there is a lack of memory resource i.e. Windows triggers a low memory notification event, memory overflow or memory pressure, the incoming records, except BLOBs, will be spooled to the file system by SSIS. The file system location is set by the BufferTempStoragePath of the data flow task. By default its value is blank, in that case the location will be based on the of value of the TEMP/TMP system variable. Likewise SSIS may choose to write the BLOB data to the file system before sending it to the destination because BLOB data is typically large and cannot be stored in the SSIS buffer. Once again the file system location for the spooling BLOB data is set by the BLOBTempStoragePath property of the data flow task. By default its value is blank.  In that case the location will be the value of the TEMP/TMP system variable. As I said, if you don't specify the values for these properties, the values of TEMP and TMP system variables will be considered as locations for spooling.  What is important is to change the default values of the BufferTempStoragePath/BLOBTempStoragePath properties and specify locations where the user executing the package (if the package is being executed by SQL Server Job, then SQL Server Agent service account) has access to these locations.  Preferably both locations should refer to separate fast drives (with separate spindles) to maximize I/O throughput and improve performance. How DelayValidation property can help you SSIS uses validation to determine if the package could fail at runtime. SSIS uses two types of validation.  First is package validation (early validation) which validates the package and all its components before starting the execution of the package.  Second SSIS uses component validation (late validation), which validates the components of the package once started. Let's consider a scenario where the first component of the package creates an object i.e. a temporary table, which is being referenced by the second component of the package. During package validation, the first component has not yet executed, so no object has been created causing a package validation failure when validating the second component. SSIS will throw a validation exception and will not start the package execution. So how will you get this package running in this common scenario? To help you in this scenario, every component has a DelayValidation (default=FALSE) property.  If you set it to TRUE, early validation will be skipped and the component will be validated only at the component level (late validation) which is during package execution.
05/27/2010 |Daniel Kohler
In the previous post I showed you how to create some Powershell scripts with intention to sync up a master and secondary DNS server, specifically by creating any missing secondary zones. In this post, I'll clean up the functions and create the main script to keep things in sync. For the sake of cleanliness, I decided to split everything up into seperate reusable scripts, I have a feeling I'm going to be reusing parts of these scripts for various different things, so here are the new scripts and contents. ############################################################### # function: zone-exists # parameters: $zoneName - the name of the zone to look for # $server - the FQDN of the server to look # $useruname - user account # $password - password # returns: true/false # Author: Daniel Kohler # blog: http://danielkohler.name # Disclaimer: use at your own risk author is not responsible # for any damage you may cause by using this # script # Copyright(c) 2010 - Icon Technology Solutions, Inc. ############################################################### param([string]$zonename,[string]$server,[parameter(mandatory=$false)]$username,[parameter(mandatory=$false)]$password); $return=$false; if(($username-ne $null)-band($password -ne $null)){ $spwd=ConvertTo-SecureString $password -AsPlainText -Force $credential=New-Object System.Management.Automation.PSCredential $username, $spwd $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $c=Get-WMIObject -Class "MicrosoftDNS_Zone" -Namespace "root\MicrosoftDNS" -ComputerName $server | where-object{$_.Name -eq $zonename} $return=$c -ne $null #close session remove-pssession -Session $s #return } else{ $c=Get-WMIObject -Class MicrosoftDNS_Zone -Namespace root\MicrosoftDNS -computername $server | where-object{$_.Name -eq $zonename} $return=$c -ne $null } return $return; ############################################################### # Function: Get-Zones # Purpose: Retrieves the particluar zone by type # specified for a given # server. # Parameters: -server (required) - the FQDN of the DNS # server # -zonetype (required) - the type of zone # (0 -primary, # 1-secondary, etc) # -username (optional) - user account # -password (optional) - password for user # account # # returns: a collection of MicrosoftDNS_Zone records # Author: Daniel Kohler # blog: http://danielkohler.name # Disclaimer: use at your own risk author is not responsible # for any damage you may cause by using this # script # Copyright(c) 2010 - Icon Technology Solutions, Inc. ############################################################### param([string]$server,[int]$zonetype,[parameter(mandatory=$false)]$username=$null,[parameter(mandatory=$false)]$password=$null); $return=$null; if(($username-ne $null)-band($password -ne $null)){ $spwd=ConvertTo-SecureString $password -AsPlainText -Force $credential=New-Object System.Management.Automation.PSCredential $username, $spwd $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $Return=Get-WMIObject -Class MicrosoftDNS_Zone -Namespace root\MicrosoftDNS -computername $server | Where-Object{($_.ZoneType -eq $zoneType) -band($_.Name -ne "TrustAnchors")} remove-pssession -Session $s } else{ $return=Get-WMIObject -Class MicrosoftDNS_Zone -Namespace root\MicrosoftDNS -computername $server | Where-Object{($_.ZoneType -eq $zoneType) -band($_.Name -ne "TrustAnchors")} } return $return; ############################################################### # function: new-secondary-zone.ps1 # parameters: $zoneName - user account name # $masterIP - delimited list of master ips # $server - server # $username - user account # $password - user account password # returns: nothing # Author: Daniel Kohler # blog: http://danielkohler.name # Disclaimer: use at your own risk author is not responsible # for any damage you may cause by using this # script # Copyright(c) 2010 - Icon Technology Solutions, Inc. ############################################################### param([string]$zonename,[string]$masterIP,[string]$server,[parameter(mandatory=$false)]$username,[parameter(mandatory=$false)]$password); if(($username-ne $null)-band($password -ne $null)){ $spwd=ConvertTo-SecureString $password -AsPlainText -Force $credential=New-Object System.Management.Automation.PSCredential $username, $spwd $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $type=1; $fileName=$zoneName+".dns"; $adminEmail="hostmaster@" +$zoneName; ([WmiClass]"\\$server\root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone( ` $zoneName, $type, $false, $filename, ` @($masterIP),$adminEmail) #close session remove-pssession -Session $s } else{ $type=1; $fileName=$zoneName+".dns"; $adminEmail="hostmaster@" +$zoneName; ([WmiClass]"\\$server\root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone( ` $zoneName, $type, $false, $filename, ` @($masterIP),$adminEmail) } And the final script to sync everything up ######################################################################### # Utility Script: This script will create secondary forward lookup # zones on the server specified when they do not # exist. It uses a primary DNS server to # determine which zones are missing # Author: Daniel Kohler # blog: http://danielkohler.name # Disclaimer: use at your own risk author is not responsible # for any damage you may cause by using this # script # Copyright(c) 2010 - Icon Technology Solutions, Inc. ######################################################################### $userName="someuser@domain.com"; $password="someusers_password"; $primaryDNS="."; $masterIP="10.10.10.10"; [array]$secondaryDNS="ns1.domain.com","ns1.domain.com"; $credential= .\new-credential.ps1 -username $userName -password $password $zones=.\get-zones.ps1 -server $primaryDNS -zoneType 1 foreach($zone in $zones) { foreach($server in $secondaryDNS) { #determine if the zone exists on the remote server $e=.\zone-exists.ps1 -zonename $zone.Name -server $server -username $username -password $password if($e -ne $true) { #we need to create this zone on the secondary server .\new-secondary-zone.ps1 -zonename $zone.Name -masterIP $masterIP -server $server -username $username -password $password } } } All of these scripts can also be found on our forum site, http://forums.iconsolution.net/viewforum.php?f=11
05/24/2010 |Daniel Kohler
This post is going to show you how to create a resuable windows powershell script to monitor a primary DNS server for the creation of new forward lookup zones, if a new zone is detected and it does not exist on the configurable secondary DNS server, it will create a new secondary zone, setup the master server and begin a zone transfer. This script has the following assumptions: The computers must on a domain. Windows Powershell 2.0 installed on all servers. Powershell script execution is enabled (Set-ExecutionPolicy unrestricted) WinRM is configured and enabled on all servers in question. Enabling WinRM on Server 2003 R2 To enable WinRM on server 2003 R2, download and install the windows poershell 2.0.  Once you have it installed run enable-psremoting and accept the prompts. Enabling WinRM on Server 2008 R2 Just open an elevated PowerShell and run enable-psremoting and follow the prompts You could use this function to create a credential for authenticating to remote servers ############################################################### # function: CreateCredential # returns: System.Management.Automation.PSCredential # parameters: $uid - user account name # $pwd - account password # example: CreateCredential "user@123.com" "somepwd" ############################################################### function CreateCredential([string] $uid, [string] $pwd) { $spwd=ConvertTo-SecureString $pwd -AsPlainText -Force return New-Object System.Management.Automation.PSCredential $uid, $spwd } I wrote the following function to test for the existance of a zone a particular server: ############################################################### # function: ZoneExists # parameters: $zoneName - the name of the zone to look for # $server - the FQDN of the server to look # $credential - a credential with rights to the server # example: ZoneExists "123.com" "ns1.123.com" [credential] ############################################################### function ZoneExists([string]$zoneName, [string]$server,[System.Management.Automation.PSCredential]$credential) { $return=0; $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $c=Get-WMIObject -Class MicrosoftDNS_Zone -Namespace root\MicrosoftDNS -computername $server | Where-Object{$_.Name -eq $zoneName} $return=$c -ne $null #close session remove-pssession -Session $s #return return $return; } And the final function needed to create the secondary zone on the specific server ############################################################### # function: CreateSecondaryZone # returns: System.Management.Automation.PSCredential # parameters: $zoneName - user account name # $masterIP - account password # $server - server # $credential - credential # example: CreateSecondaryZone "123.com" []"192.168.1.1" "ns2.123.com" [credential] ############################################################### function CreateSecondaryZone($zoneName,$masterIP,$server,$credential) { $return=0; $s=new-pssession -ComputerName $server -Credential $credential enter-pssession -Session $s $type=1; $fileName=$zoneName+".dns"; $adminEmail="hostmaster@" +$zoneName; ([WmiClass]"\\$server\root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone( ` $zoneName, $type, $false, $filename, ` @($masterIP),$adminEmail) #close session remove-pssession -Session $s #return return $return; } Part 2 brings it all together ---> All the files needed to run this solution can be found at http://forums.iconsolution.net/viewtopic.php?f=11&t=6
05/14/2010 |Daniel Kohler
This short post will demonstrate how to configure multiple sites to use SSL on the same IP using Host Header Bindings. This example is appropriate when you have a wildcard SSL or a unified communications certificate and you want to run multiple websites over port 443.  These commands will need to be run on the web server.  Just open a command prompt and navigate to the folder containing adsutil.vbs (usually c:\inetpub\adminscripts). cscript.exe adsutil.vbs set /w3svc/[site identifier]/SecureBindings ":443:[host header]" Just run this command for each site that needs to run over SSL and you are done.
11/24/2009 |Mike Lee
Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin-top:0in; mso-para-margin-right:0in; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0in; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:"Times New Roman"; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} As developers we often find ourselves torn between two different but similar technologies for a variety of reasons.  I always find myself leaning toward the Microsoft end of this spectrum whenever in doubt.  One notable exception to this “rule” of mine is something I am sure any developer is fairly familiar with, jQuery.  Javascript is unavoidable for web developers, but dealing with the document object model implemented by different browsers can be a truly frustrating task…  and then one day, in walks jQuery and provides us with a level of DOM abstraction that alleviates this giant pain in the neck. Although not exactly recent news ( http://weblogs.asp.net/scottgu/archive/2008/09/28/jquery-and-microsoft.aspx http://blog.jquery.com/2008/09/28/jquery-microsoft-nokia/ ), the fact that Microsoft now officially supports jQuery is something sure to put a smile on most of our faces.  With another official tool available I find myself yet again wondering if I should abandon one technology over the other.  Should I use jQuery for my AJAX needs, or should I use Microsoft AJAX?  Fortunately, or unfortunately depending on your viewpoint, I have to admit the answer seems to be “It depends.”     There are pros and cons to each, but from my perspective a developer (given the choice) should use whatever technology is easiest for them and fits into the projects needs.  That said, the following is an example of retrieving/sending data asynchronously using each technology.  Which you decide to use is entirely up to you. [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class WebServiceExample : System.Web.Services.WebService {     public WebServiceExample () {            }     [WebMethod]     public string GetPeople()     {         List<Person> obj = new List<Person>();         obj.Add(new Person("John", "Doe", 18));         obj.Add(new Person("Jane", "Doe", 20));         obj.Add(new Person("Jimmy", "John", 30));         return JSONHelper.Serialize<List<Person>>(obj);           }     [WebMethod]     public string UpdatePeople(List<Person> people)     {         //Do something with each person here.                return string.Empty;     } } public class JSONHelper {     public static string Serialize<T>(T obj)     {         System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());         MemoryStream ms = new MemoryStream();         serializer.WriteObject(ms, obj);         string retVal = Encoding.Default.GetString(ms.ToArray());         return retVal;     }     public static T Deserialize<T>(string json)     {         T obj = Activator.CreateInstance<T>();         MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));         System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());         obj = (T)serializer.ReadObject(ms);         ms.Close();         return obj;     } } [DataContract] public class Person {     [DataMember]     public string FirstName { get; set; }     [DataMember]     public string LastName { get; set; }     [DataMember]     public int Age { get; set; }     public Person()     {     }     public Person(string firstName, string lastName, int age)     {         FirstName = firstName;         LastName = lastName;         Age = age;     } }   In the three classes above:  WebServiceExample contains two WebMethods GetPeople - returns a JSON string consisting of three "People" UpdatePeople - Accepts a generic list of "people".  (Doesn't actually update anything in our example)  JSONHelper contains some helper methods for serializing and deserializing to and from JSON.   Person - Just a simple class holding information about a person.   Ok, so let's assume the task is to retrieve a list of people, modify some information about those people, and send the data back to be updated.  Note for both methods I am going to use a common snippet of code to help me parse JSON results.  I do this not only for native JSON support (if the browser supports it), but also to deal with data.d headaches.   You can read more about this here:  http://encosia.com/2009/07/07/improving-jquery-json-performance-and-security/ function dataFilter(data) {     var msg;     if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function')         msg = JSON.parse(data);     else         msg = eval('(' + data + ')');     if (msg.hasOwnProperty('d'))         return msg.d;     else         return msg; }       Microsoft AJAX   Add a scriptmanager to your page that has a serviceReference pointing to the appropriate web service.   <asp:ScriptManager ID="_scriptManager" runat="server">       <Services>         <asp:ServiceReference              Path="WebServiceExample.asmx" />       </Services> </asp:ScriptManager>     Make the appropriate call using the proxy generated for you by the script manager.  Note that you don't need to worry about serializing/deserializing your collection of people.     WebServiceExample.GetPeople( function OnGetPeopleSucceeded(result) {     var people = dataFilter(result);     for (var i = 0; i < people.length; i++) {     people[i].FirstName = "Johnny";     }     WebServiceExample.UpdatePeople(people,     function OnUpdatePeopleSucceeded(result) {         alert('updated');     }     ); } );               jQuery AJAX  NOTE:  With jQuery you must manually convert to and from JSON.   I elected to use the Jquery JSON plugin for this task ( http://code.google.com/p/jquery-json/ )  Add your script references :) <script type="text/javascript" src="jquery-1.3.2.js"></script> <script type="text/javascript" src="jquery.json-2.2.min.js"></script>   Make the appropriate call with the proper WebService url/method and any parameters you need.               $.ajax({                 type: "POST",                 url: "WebServiceExample.asmx/GetPeople",                 data: "{}",                 contentType: "application/json; charset=utf-8",                 dataType: "json",                 dataFilter: function(data) {                     return dataFilter(data);                 },                 success: function(msg) {                     for (var i = 0; i < msg.length; i++) {                         msg[i].FirstName = "Johnny";                     }                     var people = $.toJSON({ "people": msg });                     $.ajax({                         type: "POST",                         url: "WebServiceExample.asmx/UpdatePeople",                         data: people,                         contentType: "application/json; charset=utf-8",                         dataType: "json",                         success: function(msg) {                             alert('updated');                         }                     });                 }             });        
11/06/2009 |Mike Lee
Although I used the following method to install jQuery as a Sharepoint Farm Feature, you can obviously use this same technique for anything you want available as a SharePoint-wide feature.  I've found JQuery to be an incredible tool so I think it's more than worthy of being the main example here.  :) Step 1. Dowload the latest jQuery script and place it in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\js Step 2. Create a Control Template for jquery in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\CONTROLTEMPLATES  (Just a user control that has nothing but a script include pointing to the respective javascript file from step 1.) JqueryControl.ascx <%@ Control ClassName="jQueryControl" %><script type="text/javascript" src="/_layouts/js/jquery-1.3.2.min.js"></script> Step 3.  Create a Feature Template describing JqueryControl in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES\  (Each template being a directory with an appropriate feature.xml and <featureName>.xml…  This just points to the control template from step 2.) Please note:  When I was doing this the first time I happened to be installing both Jquery and JqueryUI as features.  In a classic forehead slap moment I completely overlooked the Id attribute of the Feature node in the feature.xml file and had duplicated the GUID in the second feature.  Needless to say, you cannot install two different features using the same Feature Id.  Avoid the forehead slap effect and generate a new GUID here:  http://msdn.microsoft.com/en-us/library/ms241442%28VS.80%29.aspx  feature.xml <?xml version="1.0" encoding="utf-8" ?><Feature Id="62D5F317-A793-4328-A250-50CBE1F5B70E"  Title="jQueryControl"  Scope="Farm"  Description="jQuery Control"  Version="1.0.0.0"  xmlns="http://schemas.microsoft.com/sharepoint/" >  <ElementManifests>      <ElementManifest Location="jQueryControl.xml" />  </ElementManifests></Feature>JqueryControl.xml <?xml version="1.0" encoding="utf-8" ?><Elements xmlns="http://schemas.microsoft.com/sharepoint/" >    <Control Id="jQueryMinifiedControl"          ControlSrc="~/_ControlTemplates/jQueryMinifiedControl.ascx"          Sequence="100" >      </Control></Elements> Step 4.  Run the following on your SharePoint server:    stsadm –o installfeature -filename JQuery\feature.xml Step 5.  Verify that the feature is enabled in:  Central Administration -> Operations -> Manage Farm Features Step 6.  Add the following DelegateControl in any page you wish to use JQuery (or in your masterpage) <SharePoint:DelegateControl ControlId="jQueryMinifiedControl" RunAt="server" /> Enjoy!
10/03/2009 |Mike Lee
 I seem to be fascinated lately with the idea of having rounded DIVs that also have transparent backgrounds.  I think it's a very cool visual effect but has always seemed problematic when attempting to make this work in different types of browsers.  The good news is that the method implemented here works for IE6, IE7, IE8, Firefox 2, Firefox 3, Safari, and Chrome.  The opaque backgrounds will work in Opera, but it would take a bit of tweaking to get the corners working.   As you probably already know (and I found out) Internet Explorer is rather troublesome (or non existent) with implementing CSS 3 features like rounded corners.  Also, even though you can create opaque DIVs in Internet Explorer, the built in approach of setting a Opacity value effects any nested children.  This is bad because it actually makes text appear opaque which is a real pain in the butt to read.  The solution to this (that seemed to work best with a variety of browsers) was to use an Opaque PNG image as a DIV backgroundimage.  Of course this removes the ability to dyamically change   Include the following: <script language="javascript" src="./scripts/jquery-1.3.2.min.js" type="text/javascript"></script> <script language="javascript" src="./scripts/browserdetect_lite.js" type="text/javascript"></script> <script language="javascript" src="./scripts/DD_roundies_0.0.2a-min.js" type="text/javascript"></script>     The following will run when the DOM is loaded:                 <script language="javascript" type="text/javascript">      $(document).ready(function() {          $('.opaque').css('background-image','url(./Images/back.png)');          DD_roundies.addRule('.rounded', '8px', !browser.isIE);      }); </script> I could have created a class in my CSS file to handle the opaque background image, but in learning a bit about jquery I felt compelled to show how a css element can be applied on the fly with very little code.  An important note here is that IE6 (and I think IE7) will NOT natively use a PNG as a background image properly.  This is solved in this case because of a fix implemented by DD_Roundies.  (Two birds with one stone!  Yipee)   DD_Roundies will add rounded corners to elements in one of two ways (three if you count IE8).  If the browser is CSS 3 compliant (or mostly compliant) it will use the appropriate border-radius property.  Because Internet Explorer does not support this is will use VML to draw the corners.    MyStyles.css (optional of course)  .box {       padding:20px;       border: 1px #767878 solid; }   Add the following class attributes anywhere you want this effect: <div id="myMaindDiv" class="rounded opaque box">     ... content here ... </div>       http://www.dillerdesign.com/experiment/DD_roundies/ http://jquery.com/

Customer Information

Icon Technology Solutions, Inc. is committed to do everything we can to maintain our customer's privacy. Icon Technology Solutions, Inc. signup forms and control panel uses industry-standard Secure Sockets layer (SSL) to encrypt all personal information. Access to customer account information is password protected. We provide a LOGOUT button in the control panel which will terminate the session, so that no future users on the same computer can access the control panel.

Information Disclosure

Icon Technology Solutions, Inc. may disclose personally identifiable information, member content on Icon Technology Solutions, Inc. servers, and/or stats and log files, without notice to comply with a legal order or federal/state law enforcement request. For new domain name registration, Icon Technology Solutions, Inc. is required to provide our Domain Registrar partner with domain name owner contact information which may become publicly available. Icon Technology Solutions, Inc. may disclose personally identifiable information in the course of providing web hosting services ordered by the customer to its lawyers or agent to collect a debt. Icon Technology Solutions, Inc. will never sell or disclose our member's personally identifiable information to any advertiser, partner or third party except as provided above. Icon Technology Solutions, Inc. may disclose aggregate statistical data to potential partners. At no time will this aggregate data contain personally identifiable information. Icon Technology Solutions, Inc. may disclose aggregate statistical data for press releases, presentations, reports, or white papers that we may make available to partners or to the public. At no time will this aggregate data contain personally identifiable information.

Public Forum

Icon Technology Solutions, Inc. hosts public forums. Users of the forum should exercise caution when disclosing personal information as any posts become public information.

Cookies and Website Traffic Statistics

Icon Technology Solutions, Inc. uses cookies and website traffic statistics to help improve our website and services. Icon Technology Solutions, Inc. uses cookies to analyze repeat visits to our website. Icon Technology Solutions, Inc. uses website traffic statistics to analyze how visitors use our website and control panel. Icon Technology Solutions, Inc. uses cookies to operate our Forum. Icon Technology Solutions, Inc. uses cookies in the control panel to help facilitate customer account management. Icon Technology Solutions, Inc. uses cookies to analyze our marketing effectiveness. Icon Technology Solutions, Inc. may accept third party advertisement or may refer customers to third party services on our website, control panel, newsletters, or email. Third party services and advertisers may set cookies. Use of their cookie is subject to the third party's privacy policies.

Policy Updates

Icon Technology Solutions, Inc. reserves the right to modify its policies at any time. Any modification is effective upon posting on our website.