Thursday, October 4, 2012

It's easy to get back a collection from MongoDB filtered by a match on a property.

The middle method below does the deed:

using System.Collections.Generic;
using System.Configuration;
using MongoDB.Driver;
using MongoLogin.Core;
using MongoLogin.Core.Interfaces.DataIntegration;
using MongoDB.Driver.Builders;
namespace MongoLogin.Infrastructure.DataIntegration
{
   public class UserAccountRepository : IUserAccountRepository
   {      
      public int GetCountOfExistingUserAccounts()
      {
         var server =
               MongoServer.Create(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[0]]);
         var database =
               server.GetDatabase(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[1]]);
         var allRecords = database.GetCollection<UserAccountDataTransferObject>
               (ConfigurationManager.AppSettings[CommonMagicStrings.
               WebConfigAppSettings()[2]]);
         var query = Query.Matches(CommonMagicStrings.Status(),
               CommonMagicStrings.StatusRegularExpression());
         var legitimateResults = allRecords.Find(query);
         return (int)legitimateResults.Count();
      }
      
      public List<UserAccount> GetUserAccountsForEmailAddress(string email)
      {
         var server =
               MongoServer.Create(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[0]]);
         var database =
               server.GetDatabase(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[1]]);
         var allRecords = database.GetCollection<UserAccountDataTransferObject>
               (ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[2]]);
         var query = Query.Matches(CommonMagicStrings.Email(), email);
         var legitimateResults = allRecords.Find(query);
         List<UserAccount> userAccounts = new List<UserAccount>(){};
         foreach (UserAccountDataTransferObject userAccount in legitimateResults)
         {
            userAccounts.Add(new UserAccount(userAccount.Email,userAccount
                  .Password,userAccount.Status));
         }
         return userAccounts;
      }
      
      public void SaveNewUserAccount(UserAccount userAccount)
      {
         var server =
               MongoServer.Create(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[0]]);
         var database =
               server.GetDatabase(ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[1]]);
         var allRecords = database.GetCollection<UserAccountDataTransferObject>
               (ConfigurationManager.AppSettings[
               CommonMagicStrings.WebConfigAppSettings()[2]]);
         var dto = new UserAccountDataTransferObject
                                 {
                                    Email = userAccount.Email,
                                    Password = userAccount.Password,
                                    Status = userAccount.Status.ToString()
                                 };
         allRecords.Insert(dto);
         allRecords.Save(dto);
      }
   }
}

 
 

This is an expansion on this code I've been writing. My interface now looks as such:

using System.Collections.Generic;
namespace MongoLogin.Core.Interfaces.DataIntegration
{
   public interface IUserAccountRepository
   {
      int GetCountOfExistingUserAccounts();
      void SaveNewUserAccount(UserAccount userAccount);
      List<UserAccount> GetUserAccountsForEmailAddress(string email);
   }
}

 
 

My repository wrapper:

using System.Collections.Generic;
using MongoLogin.Core.Interfaces.DataIntegration;
namespace MongoLogin.Core.InfrastructureWrappers.DataIntegration
{
   public class UserAccountRepositoryWrapper
   {
      public IUserAccountRepository Repository { get; set; }
      
      public UserAccountRepositoryWrapper(IUserAccountRepository repository)
      {
         Repository = repository;
      }
      
      public string
            AttemptToSaveNewUserAccountReturningEitherSerializationOrError(
            UserAccount userAccount)
      {
         int numberOfUsers = Repository.GetCountOfExistingUserAccounts();
         if (numberOfUsers == 0) userAccount.Status = UserStatus.Administrative;
         List<UserAccount> preexistingComparableAccounts =
               Repository.GetUserAccountsForEmailAddress(userAccount.Email);
         if (preexistingComparableAccounts.Count > 0)
         {
            return CommonMagicStrings.UserAccountAlreadyExists();
         } else {
            Repository.SaveNewUserAccount(userAccount);
            return userAccount.FlattenUserAccount();
         }
      }
   }
}

 
 

The wrapper's test:

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoLogin.Core.InfrastructureWrappers.DataIntegration;
using MongoLogin.Core.Tests.InterfaceTestingHelpers.DataIntegration;
namespace MongoLogin.Core.Tests.InfrastructureWrapperTests.DataIntegration
{
   [TestClass]
   public class UserAccountRepositoryWrapperTests
   {
      [TestMethod]
      public void SaveNewUserAccountUpdatesUserStatusWhenAppropriateTest()
      {
         UserAccount userAccount = new UserAccount("tomjaeschke@tomjaeschke.com",
               "foo");
         StubbedUserAccountRepository stub = new StubbedUserAccountRepository();
         stub.ValueToReturnForGetCountOfExistingUserAccounts = 0;
         stub.UserAccountsToReturnFromAnAttemptedEmailMatch = new
               List<UserAccount>() { };
         UserAccountRepositoryWrapper repository = new
               UserAccountRepositoryWrapper(stub);
         string serialization = repository
               .AttemptToSaveNewUserAccountReturningEitherSerializationOrError(
               userAccount);
         Assert.AreEqual(stub.UserAccountHandedIntoSaveNewUserAccount.Status,
               UserStatus.Administrative);
         Assert.AreEqual(serialization,
               "tomjaeschke@tomjaeschke.com|foo|Administrative");
         
         userAccount = new UserAccount("fevercheese@gmail.com", "bar");
         stub = new StubbedUserAccountRepository();
         stub.ValueToReturnForGetCountOfExistingUserAccounts = 1;
         stub.UserAccountsToReturnFromAnAttemptedEmailMatch = new
               List<UserAccount>() { };
         repository = new UserAccountRepositoryWrapper(stub);
         serialization = repository
               .AttemptToSaveNewUserAccountReturningEitherSerializationOrError(
               userAccount);
         Assert.AreEqual(stub.UserAccountHandedIntoSaveNewUserAccount.Status,
               UserStatus.Awaiting);
         Assert.AreEqual(serialization, "fevercheese@gmail.com|bar|Awaiting");
         
         userAccount = new UserAccount("fevercheese@gmail.com", "bar");
         stub = new StubbedUserAccountRepository();
         stub.ValueToReturnForGetCountOfExistingUserAccounts = 1;
         stub.UserAccountsToReturnFromAnAttemptedEmailMatch = new
               List<UserAccount>() { new UserAccount(
               "fevercheese@gmail.com", "bar") };
         repository = new UserAccountRepositoryWrapper(stub);
         string error = repository.
               AttemptToSaveNewUserAccountReturningEitherSerializationOrError(
               userAccount);
         Assert.AreEqual(error, CommonMagicStrings.UserAccountAlreadyExists());
      }
   }
}

 
 

The wrapper test's stub for the repository interface:

using System.Collections.Generic;
using MongoLogin.Core.Interfaces.DataIntegration;
namespace MongoLogin.Core.Tests.InterfaceTestingHelpers.DataIntegration
{
   public class StubbedUserAccountRepository : IUserAccountRepository
   {
      public int ValueToReturnForGetCountOfExistingUserAccounts { get; set; }
      public List<UserAccount> UserAccountsToReturnFromAnAttemptedEmailMatch {
            get; set; }
      public UserAccount UserAccountHandedIntoSaveNewUserAccount { get; set; }
      
      public int GetCountOfExistingUserAccounts()
      {
         return ValueToReturnForGetCountOfExistingUserAccounts;
      }
      
      public List<UserAccount> GetUserAccountsForEmailAddress(string email)
      {
         return UserAccountsToReturnFromAnAttemptedEmailMatch;
      }
      
      public void SaveNewUserAccount(UserAccount userAccount)
      {
         UserAccountHandedIntoSaveNewUserAccount = userAccount;
      }
   }
}

 
 

And finally, magic strings:

namespace MongoLogin.Core
{
   public static class CommonMagicStrings
   {
      public static string AtSymbol()
      {
         return "@";
      }
      
      public static string Email()
      {
         return "Email";
      }
      
      public static string EmailRegularExpression()
      {
         return @"^\w+([-+.']\w+)*@\w+([-+.']\w+)*\.\w+([-+.']\w+)*$";
      }
      
      public static string EmailRegularExpressionFailure()
      {
         return "The email address was not valid.";
      }
      
      public static string Metadata()
      {
         return "Metadata";
      }
      
      public static string Password()
      {
         return "Password";
      }
      
      public static string PasswordConfirmationFailure()
      {
         return "The two passwords provided did not match.";
      }
      
      public static string PasswordRegularExpression()
      {
         return @"^[a-zA-Z0-9]{6,20}$";
      }
      
      public static string PasswordRegularExpressionFailure()
      {
         return "Passwords should be six to twenty characters and contain only capital
               letters, lowercase letters, and digits.";
      }
      
      public static string PipeSymbol()
      {
         return "|";
      }
      
      public static string Status()
      {
         return "Status";
      }
      
      public static string StatusRegularExpression()
      {
         return "/^([A].*)$/";
      }
      
      public static string UserAccountAlreadyExists()
      {
         return "An account with the email address specified already exists.";
      }
      
      public static string[] WebConfigAppSettings()
      {
         return new string[]
               {
                  "MongoLoginConnection",
                  "MongoLoginDatabase",
                  "MongoLoginCollection"
               };
      }
   }
}

Create drop down lists for user inputs in SSRS.

Let's say you have a stored procedure that takes two input parameters to generate results. What if, when a user enters values for the sproc in an SSRS report, you wished to restrain their values to a series of options. You could do so like this:

<ReportParameters>
   <ReportParameter Name="DoomDate">
      <DataType>String</DataType>
      <AllowBlank>true</AllowBlank>
      <Prompt>What day will the world end?</Prompt>
      <ValidValues>
         <DataSetReference>
            <DataSetName>DarkDates</DataSetName>
            <ValueField>dtLabel</ValueField>
            <LabelField>dtLabel</LabelField>
         </DataSetReference>
      </ValidValues>
   </ReportParameter>
   <ReportParameter Name="SkyColor">
      <DataType>String</DataType>
      <Prompt>What color is the sky?</Prompt>
      <ValidValues>
         <ParameterValues>
            <ParameterValue>
               <Value>0</Value>
               <Label>Black</Label>
            </ParameterValue>
            <ParameterValue>
               <Value>1</Value>
               <Label>Blue</Label>
            </ParameterValue>
         </ParameterValues>
      </ValidValues>
   </ReportParameter>
</ReportParameters>

 
 

The second DataType above has its selectable values hard-coded. The first gets its values populated by data like so:

<DataSet Name="DarkDates">
   <Query>
      <DataSourceName>Whatever</DataSourceName>
      <CommandText>
         SELECT DISTINCT CONVERT(VARCHAR(10),PaymentDate,111) AS dtSort,
               CONVERT(VARCHAR(10),PaymentDate,101) dtLabel
         FROM FutureEvents
         ORDER BY CONVERT(VARCHAR(10),PaymentDate,111) DESC
      </CommandText>
      <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
   </Query>
   <Fields>
      <Field Name="dtSort">
         <DataField>dtSort</DataField>
         <rd:TypeName>System.String</rd:TypeName>
      </Field>
      <Field Name="dtLabel">
         <DataField>dtLabel</DataField>
         <rd:TypeName>System.String</rd:TypeName>
      </Field>
   </Fields>
</DataSet>

 
 

The DataTypes will create drop down lists. Their values get associated to the stored procedure like so:

<Query>
   <DataSourceName>Whatever</DataSourceName>
   <QueryParameters>
      <QueryParameter Name="@DoomDateInSproc">
         <Value>=Parameters!DoomDate.Value</Value>
      </QueryParameter>
      <QueryParameter Name="@SkyColorInSproc">
         <Value>=Parameters!SkyColor.Value</Value>
      </QueryParameter>
   </QueryParameters>
   <CommandType>StoredProcedure</CommandType>
   <CommandText>sp_SomethingErOther</CommandText>
</Query>

 
 

The three blobs of XML here are three different bits of one SSRS report using the sp_SomethingErOther stored procedure.

Wednesday, October 3, 2012

You can interface with AJAX JSON from an ASP.NET web forms project too.

I have persevered in unraveling this mystery. Here is how one reaches out to AJAX JSON (AJAJ) via a web forms application. First, you need to have something like this in a web form:

<script src="/Scripts/jquery.js" type="text/javascript"></script>
<script src="/Scripts/json.js" type="text/javascript"></script>
<script type="text/javascript">
   jQuery(document).ready(function () {
      jQuery.ajax({
         type: "POST",
         url: "/Default.aspx/SayHello",
         contentType: "application/json; charset=utf-8",
         data: "{ recipient: \"World\" }",
         dataType: "json",
         success: function (result) {
            alert(result.d);
         },
         error: function (result) {
            alert('failure');
         }
      });
   });
</script>

 
 

Finally, you need to have something like this in the code behind:

using System;
using System.Web.Services;
namespace WindowsFormsApplication
{
   public partial class _Default : System.Web.UI.Page
   {
      protected void Page_Load(object sender, EventArgs e)
      {
      }
      
      [WebMethod(EnableSession = true)]
      public static string SayHello(string recipient)
      {
         return "Hello " + recipient;
      }
   }
}

What stored procedures touch a given table in MSSQL?

Bradley Estep showed me this trick today for fishing for something that touches something else in a database:

DECLARE @Search varchar(255)
SET @Search='
SOMETHINGTOMATCHON'
SELECT DISTINCT
o.name AS Object_Name,o.type_desc
FROM sys.sql_modules m
INNER JOIN sys.objects o ON m.object_id=o.object_id
WHERE m.definition Like '%'+@Search+'%'
ORDER BY 2,1

 
 

I fed in the name of a table and was informed of the one stored procedure (in over one hundred) that touched the table in question.

Tuesday, October 2, 2012

TypeScript

https://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript is an excellent Channel 9 movie in which Anders Hejlsberg (the keeper of C#) gives a firehose of information on TypeScript which is vaguely akin to CoffeeScript in that one may write impossible JavaScript code that then compiles to real JavaScript code. The stuff that is empowered by TypeScript is optional static types, classes, and modules, the fundamentals for making a sizable yet maintainable application.

Share photos on twitter with Twitpic

This example shows that one cannot have a .name property hanging off of a string without the compiler objecting:

Share photos on twitter with Twitpic

changing element styles the plain old JavaScript way

I had to refactor this...

$('input[name=service]').live('click', function () {
   var service = document.getElementsByName("service");
   if (service[0].checked) {
      $('#pecs').attr('style', 'font-size: 1.5em;');
      $('#electric').attr('style', 'font-size: 0.75em;');
      $('#reviewsummary').attr('style', 'display: inline;');
      $('#reviewdetails').attr('style', 'display: inline;');
      $('#controls').attr('style', 'display: block;');
      $('#payTypes').attr('disabled', '');
   }
   if (service[1].checked) {
      $('#pecs').attr('style', 'font-size: 0.75em;');
      $('#electric').attr('style', 'font-size: 1.5em;');
      $('#reviewsummary').attr('style', 'display: none;');
      $('#reviewdetails').attr('style', 'display: none;');
      $('#controls').attr('style', 'display: block;');
      $('#payTypes').val("1");
      $('#payTypes').attr('disabled', 'disabled');
   }
});

 
 

To this...

$('input[name=service]').live('click', function () {
   var service = document.getElementsByName("service");
   if (service[0].checked) {
      var pecs = document.getElementById("pecs");
      var electric = document.getElementById("electric");
      var reviewsummary = document.getElementById("reviewsummary");
      var reviewdetails = document.getElementById("reviewdetails");
      var controls = document.getElementById("controls");
      var payTypes = document.getElementById("payTypes");
      pecs.style.fontSize = "1.5em";
      electric.style.fontSize = "0.75em";
      reviewsummary.style.display = "inline";
      reviewdetails.style.display = "inline";
      controls.style.display = "block";
      payTypes.disabled = false;
   }
   if (service[1].checked) {
      var pecs = document.getElementById("pecs");
      var electric = document.getElementById("electric");
      var reviewsummary = document.getElementById("reviewsummary");
      var reviewdetails = document.getElementById("reviewdetails");
      var controls = document.getElementById("controls");
      var payTypes = document.getElementById("payTypes");
      pecs.style.fontSize = "0.75em";
      electric.style.fontSize = "1.5em";
      reviewsummary.style.display = "none";
      reviewdetails.style.display = "none";
      controls.style.display = "block";
      payTypes.value = "1";
      payTypes.disabled = true;
   }
});

 
 

...as the jQuery stuff was causing some sort of conflict with some other JavaScript code that my boss, Nathan Carroll, wrote.

Monday, October 1, 2012

going places with JavaScript

Open a new window to another place:

$('#foo').bind('click', function () {
   window.open('http://www.example.com/','_blank');
});

 
 

Take the current window to another place:

$('#foo').bind('click', function () {
   window.location = "http://www.example.com/";
});