custom software development to help your business take flight™

Deploying Reports Built with SSRS 2008 R2 to SSRS 2008 non-R2

Posted by Joe Wilson on Sunday, March 18, 2012 2:03 PM

Non-R2R2I’ve got SQL Server 2008 R2 Express installed on my primary development machine, and I create SSRS reports on this box.  The problem is, I’ve got one customer with SQL Server 2008.  And yes, Microsoft changed the RDL file format between SSRS 2008 and SSRS 2008 R2, so SSRS 2008 can’t read SSRS 2008 R2 RDL files.

So how you you get around this without setting up VMs with both?  It’s not elegant, but here’s what I do:

1) On your SSRS project properties with all your reports, change the Target Server Version to SQL Server 2008 (and not SQL Server 2008 R2).

2) Get your local dev box SSRS R2 server running if it’s not already.

3) Deploy the report project to your local SSRS R2 server.

4) Go to your report management site (usually http://localhost:Reports) and download the report.  This will save out the RDL for you.

5) Now when you deploy this report to the non-R2 SSRS server, it will be the correct, non-R2 format!

The crucial steps are setting that Target Server Version and deploying.  That’s where the Visual Studio report project converts the RDL file to the format you need it to be.  After that, the downloading is just a way to get a copy of the report in the non-R2 format.

Now you can deploy the RDL to the customer’s non-R2 SSRS server, without changing your dev box.

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Push to AppHarbor on every push to GitHub

Posted by Joe Wilson on Tuesday, October 11, 2011 1:21 PM

If you’re using GitHub as your shared, online, git repository and you’re using AppHarbor for continuous integration and deployment, you really have two git repositories – the GitHub one and the AppHarbor one.

AppHarbor instructions help you set up a remote to this git repository so you can push to it whenever you like, but that means you have two steps on most commits:

git push origin master

to push your code up to your GitHub repo, and:

git push appharbor master

to push your code up to the AppHarbor repo.  Because AppHarbor doesn’t support SSH yet (only HTTPS is supported now), you also have to enter your password.  Not a giant hassle, but what if you could get rid of that last little bit of friction?

GitHub Service Hooks

GitHub Service Hooks run after a push to GitHub, and there is one to fire off your AppHarbor build/test/deploy.  It’s under your GitHub repo > Admin > Service Hooks.

Once you’re there, the instructions are pretty simple.

  1. Go to your application's main page on AppHarbor and find the "Create build URL". Example: https://appharbor.com/application/{application_slug}/build?authorization={token}
  2. "token" is the value of the "authorization" parameter.
  3. "application_slug" is your application's unique identifier.
  4. If your GitHub repository is private you need to add the "apphb" GitHub user as a collaborator. This enables AppHarbor to download the source code.

Here’s where you can find the values for steps 1-3 in AppHarbor:

Step #4 can be skipped if you have a public repo.  If you’re using private repos, add the “apphb” GitHub user to a GitHub team with “pull” grants.

All done!

Next time you do

git push origin master

your code will be pushed up to GitHub and AppHarbor will grab the latest code from GitHub (not from the AppHarbor repo anymore), build it, test it, and if the tests pass, deploy it.  All in one step!

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Presentation: Rails vs .NET

Posted by Joe Wilson on Friday, August 26, 2011 10:12 AM

I had a lot of fun speaking at the inaugural Boulder Tech Throwdown last night.  The topic was Ruby on Rails vs. ASP.NET MVC.  Thanks to Ely Lucas for doing an awesome job (as usual) co-presenting with me on the ASP.NET MVC side.

The follow up panel discussion with the Ruby on Rails guys was really high quality, thanks to insights and comments from Collin Schaafsma and Ryan Cook.

Thanks also to Paul Sabini, Fernando Cardenas, and George Morris for organizing the meetup and for the invite.

The slides and code can be downloaded here.

Tags: ,
Categories: Presentations


kick it on DotNetKicks.com shout it on DotNetShoutOut

Sessionless MVC without losing TempData

Posted by Joe Wilson on Thursday, June 30, 2011 11:32 PM

I've blogged before about making your MVC controllers sessionless.  The knock on sessionless controllers is that TempData is off the table because it uses Session as its data store.

If you see the TempData name and dismiss it, thinking it's another dictionary like Session[] and ViewData[] and you're waaaay past that since your mister type-safe, take another look.  The neat thing about TempData is that it lasts for one more page load and then "poof" - it's gone.  It self destructs as soon as it has been read.

Sure, it's a dictionary with magic string keys, but it's a great place to store message like "Your changes were saved" when you redirect to another page.

So how do we get the benefits of TempData as an ephemeral application message store, but go all-in on the web farm with sessionless controllers?

Cookies!

I can hear you groaning.  Cookies are old school!  They can't hold much information!  They aren't secure!

Fine, don't put much in there, and don't put your secret fried chicken recipe in there.  We're just going to use this as a little string to tell the user everything is OK or it's not OK.

TempData uses a provider model for the data store, and Session is the default data store.  But you can get a cookie data store, CookieTempDataProvider, with Mvc3Futures NuGet package:

image

This should work as a TempData provider, but now it has to be wired into the application.  Here's how you can do that:

    public class BaseController : Controller
    {
        protected override ITempDataProvider CreateTempDataProvider()
        {
            return new CookieTempDataProvider(HttpContext);
        }
    }

Tags: , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Running SpecFlow and WatiN tests with TeamCity and AppHarbor

Posted by Joe Wilson on Thursday, June 2, 2011 10:44 PM

If you're using SpecFlow and WatiN to automate your web testing, things work great on localhost, but tend to fall apart on the continuous integration server.  It's a "chicken or the egg" paradox.  If the new code hasn't been deployed yet, it can't be externally tested with WatiN, but it shouldn't be deployed until all the tests have passed.  What are you supposed to do?

TeamCity

If your SpecFlow and WatiN tests are in their own assembly (something like MyProject.AcceptanceTests.dll), and you're using TeamCity, it's easy to run your unit tests and integration tests, then deploy the code to a web server, then run your acceptance tests in a separate build step.  It's just a matter of breaking up the steps and designating which test assemblies will be run at which time.

This step in the screen shot below is running the unit tests and integration tests.  A separate, later step will run the tests in the **\*AcceptanceTests.dll assembly after the code has been deployed to the web server.

image

AppHarbor

imageIf you're using AppHarbor to run your tests on check in with "git push appharbor master", (and you should - it's super easy), you don't want to run your web tests until the code is deployed, but AppHarbor doesn't deploy anything until all the tests pass.

What we want is for AppHarbor to ignore the web automation tests until the code is deployed.  AppHarbor flips a *.config appSetting key named "Environment" to "Test" when it's testing and to "Release" when the code is deployed.  So while your tests are running, your App.config in your test project should look something like this:

<appSettings>
  <add key="Environment" value="Test"/>
</appSettings>

We can take advantage of this appSetting test runner change to tell SpecFlow to ignore this set of tests, which allows AppHarbor to continue running other tests and deploying the code.

This is not be the most elegant way to do this, but I got this working today:

[Binding]
public class MyStepDefinition
{
    [BeforeFeature]
    public void BeforeFeature()
    {
        if (ConfigurationManager.AppSettings["Environment"] == "Test")
            Assert.Ignore();
    }

    // Rest of step definition code...
}

The BeforeFeature attribute tells the SpecFlow test runner to execute that method before each feature.  With a quick check on the Environment appSetting value, we can tell AppHarbor to ignore this test and continue processing.  This will ignore all scenarios in all feature files.  Since all my scenarios are web automation tests, that works for me.

But what if you have some scenarios that rely on web automation testing and others that don't?  A more targeted approach would be to set a SpecFlow tag, like @web over the SpecFlow scenarios that require web automation testing to pass.  Then in the [BeforeScenario("web")] handlers for that tag, you could set Assert.Ignore to skip those scenarios while executing all other scenarios.

[BeforeScenario("web")]
public void BeforeScenario()
{
    if (ConfigurationManager.AppSettings["Environment"] == "Test")
        Assert.Ignore();
}

Once your non-web automation tests have passed and the code is deployed, you can point your local test runner at the AppHarbor URL and test against the newly deployed web app.

Tags: , , , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Want to work on a green field ASP.NET MVC project?

Posted by Joe Wilson on Thursday, June 2, 2011 6:18 PM

I'm assembling a team to work with me on a green field ASP.NET MVC project.  We will be using ASP.NET MVC 3, an ORM (NHibernate or EF Code First), SQL Server 2008, dependency injection (Ninject or Castle Windsor), and ATDD and TDD (Specflow, Watin, NUnit, and Moq).  If you've done some but not all of these things, I'll teach you the rest to fill in the gaps.

This project will be run using lean methods, so we'll pull in work only when the current task is completely done, meaning the product owner has accepted it and it's ready to go live.  We'll spend a lot of time getting the acceptance criteria just right before we build anything, so there will be lots of small, just-in-time conversations with the product owner.

We'll have flexible hours and do a lot of remote work, but we'll get together for designing and pair programming several days a week, also.  This will be done face-to-face, ideally, but remote web-cam/desktop-sharing pairing is an option, too.  We'll have to tweak this as we go to be sure communication isn't slipping and the work is getting done to the customer's expectations.

For more details or to apply, please check out the careers section.

Tags: , , , , , , , , , , , ,
Categories: Business


kick it on DotNetKicks.com shout it on DotNetShoutOut

Why I'm using Moq instead of Rhino Mocks these days

Posted by Joe Wilson on Thursday, March 10, 2011 10:29 AM

On my last greenfield project I got to pick the unit testing and mocking tools.  I've been a regular Rhino Mocks user for a long time, but I've seen lots of code samples with Moq and liked the syntax, so I gave it a try.

I have to say, I did prefer Moq slightly to Rhino Mocks.  The newer Arrange, Act, Assert (AAA) style syntax in Rhino Mocks is a huge improvement over the old Record/Replay mess.  But Moq has the benefit of being born at the right time and has AAA style calls without the burden of supporting deprecated syntax.  This means Moq has cleaner documentation, fewer options, and fewer ways to get confused by the API.  I really couldn't find anything I needed to do in Moq that I couldn't do.  I did get a little tripped up having to get the object out of the mock, with myMock.Object calls, but that wasn't a big deal.

Here's the NuGet Moq install package syntax to add Moq to your unit test project:

image

I'm using mocking frameworks less these days.  Instead, I'll write a fake object myself or just try to avoid interaction testing altogether.  But if I needed to pull one off the shelf today, I'd grab Moq first.

Tags: , , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Fixing screen saver wait time of 999 minutes on a Dell laptop

Posted by Joe Wilson on Wednesday, March 9, 2011 11:12 PM

I have a Dell Precision M4500 with Windows 7 and ran into a problem with the screen saver not coming on.  Rebooting didn't fix it and calling Dell technical support didn't help ("You could reformat, I guess."). 

My screen saver dialog looked like this with 999 minutes in the wait time:

SNAGHTML1e594b9

If I clicked Preview, the screen would go blank like it was supposed to, so it wasn't a video card thing.  When I set the wait time to 10 minutes and clicked OK, then opened the dialog box again, my value of 10 minutes was saved, but the screen saver never turned on.

Finally, I found this dialog in the Dell System and Manager under Display Settings:

SNAGHTML1e9726b

See the "Disable alarms and timers for Presentations" check box?  I had that checked, so I unchecked it and the screen saver started working normally again.  I wasn't in Presentation mode, but this Dell app didn't seem to know that.

I hope this is helpful to someone stuck on the same issue.

Tags:
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Using CRM auto filtering in custom reports with complex SQL

Posted by Joe Wilson on Sunday, February 13, 2011 4:55 PM

Report prefiltering in Microsoft CRM 4.0 is a very cool feature - when it works.  The normal ways of setting up this auto filtering feature in your custom CRM reports are 1) special aliases, and 2) SQL strings.

Special aliases

The alias approach is the simplest one to use.  If you have a report that needs prefiltering, change your SQL from this:

select firstname, lastname 
from FilteredContact

to this:

select firstname, lastname 
from FilteredContact AS CRMAF_FilteredContact
The trick is the alias.  All you need to do is add an alias with"CRMAF_" in front of the view name, and CRM will rip out your SQL at report runtime and replace it with a custom SQL statement.  I think the acronym must stand for CRM Auto Filter.  By using a special alias CRM recognizes, the actual SQL run on your server will be similar to this, where contacts are prefiltered for city = 'Denver'.

select firstname, lastname 
from (select contact0.* 
      from FilteredContact as contact0 
      where address1_city  = 'Denver') AS CRMAF_FilteredContact

SQL strings

The other route you can go is mash together SQL strings and get a parameter from CRM that is the prefilter SQL statement.  You've probably done this kind of this kind of thing before:

declare @sqlstring varchar(max)
set @sqlstring = 'select firstname, lastname 
from (' + @CRM_FilteredContact + ') AS MyFilteredContacts '
exec (@sqlstring)

This really isn't bad when you have a small SQL statement, but you probably wouldn't need to create a custom CRM report if it was a simple SQL statement, right?  The CRM users could create their own simple report inside CRM for that.

When the SQL statement gets complex, you have quote and string bugs.  When the SQL gets lengthy, you can't have over a certain number of characters in the SQL string or you have to split it and you end up with:

exec (@sqlstring1 + @sqlstring2 + @sqlstring3)

You can get it to work, but it's pretty yucky. 

The problem

I much prefer the alias approach.  It's much easier to read, and the aliases are not too much trouble to add in and get prefiltering in CRM for free.

The problem is, the alias technique breaks down when the queries get more complex or you need multiple datasets in your report using the same prefiltering.  Here are the cases I've found and the workarounds.

Dataset based on a union query

If you have a query with a union statement, like:

select firstname, lastname 
from FilteredContact AS CRMAF_FilteredContact
where address1_city = 'Denver'
union
select firstname, lastname 
from FilteredContact AS CRMAF_FilteredContact
where address1_city = 'Highlands Ranch'

CRM will do the alias filtering trick, but only for the first select.  The second select in this query will not be filtered at all.

The fix I've come up with uses SQL temp tables.  Maybe not the best approach, but I had a lot of reports that were not auto filtering as expected, and this has worked so far:

select * 
into #FilteredContact
from FilteredContact AS CRMAF_FilteredContact

select firstname, lastname 
from #FilteredContact
where address1_city = 'Denver'
union
select firstname, lastname 
from #FilteredContact
where address1_city = 'Highlands Ranch'

drop table #FilteredContact

This let's CRM do what it wants to, and swaps out your SQL where it finds the CRMAF_FilteredContact alias the first time.  It also let's you leave the rest of your SQL pretty much intact.

Dataset based on multiple queries selecting into a temp table

I had another query that was suffering the same problem, but this query was a little different.  I needed the data displayed in columns, so I created a temp table and populated it with selects.  There were multiple selects in the query filling up the columns in this temp table.  Everything ran great without auto filtering.

But with auto filtering, the same thing happened.  The first select statement got filtered.  The ones after that were untouched.  The fix I used was the same.  I created a temp table, populated it with the auto filtered data, then selected off that temp table throughout. 

To be a good TempDB citizen, I dropped the temp table at the end of the query.  SQL Server does the temp table drop for you when the table is out of scope, but it helps to have the drop statement in there when testing the query in SQL Server Management Studio and running it multiple times in the same query window.

Reports with multiple datasets

This technique works if you have a complex query that needs auto filtering.  But what if you have multiple datasets in your report, and they all need to be auto filtered?

In one report, the queries were very similar.  I had two datasets that were identical expect one used report parameter A and one used report parameter B.  This was to compare two funnels for two different time periods.  Auto filtering worked fine on the first dataset and funnel, but didn't do anything on the second dataset or funnel.

The fix in this case was to create one dataset that didn't filter on either report parameter A or parameter B.  Then in the report, have the funnel controls themselves do the filtering based on the report parameters.  Most SQL Server Reporting Services data controls have a filter property.  I've never really used them before now, since it almost never makes sense to pull all the data from the database and then filter inside the report.  I'd rather filter on the database first.  However, in this case, the control filters helped and I got the result I wanted because there was one dataset with one CRMAF_ alias.

On another report, there were three charts built using three different datasets.  The datasets were the same except for the group by clause.  I was able to use the same approach and condense these to one dataset with no group by clause, then do the grouping in the chart controls.  Again, it made me feel a little bad that the data wasn't already summed and grouped when it got to the chart control, but at least it was working.

Tags: , ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Autocomplete dropdown with jQuery UI and MVC

Posted by Joe Wilson on Friday, February 4, 2011 11:03 AM

You know the autocomplete dropdown.  It has become ubiquitous, and customers now expect them in their web apps.  "Can't you just set autocomplete=true or something?"  It's not quite that easy with ASP.NET MVC, but it's pretty simple.

We want to set up a text box on a web page that uses jQuery to call back to a controller action as the user types.  The action method will return a JSON array of values that match what the user has typed so far.  Each time they type and pause for a second, the screen should show the new matching records.

The view

First, we'll work on the view.  Set a reference to jQuery and to jQuery UI.  These are included with new MVC 3 projects (look in the Scripts folder), or you can find a CDN and reference them there.  I've got this in my view's head section:

<head>
    <title>Autocomplete Test </title>
    <script src="<%: Url.Content("~/Scripts/jquery-1.4.4.min.js")%>" type="text/javascript"></script>
    <script src="<%: Url.Content("~/Scripts/jquery-ui.min.js")%>" type="text/javascript"></script>
</head>

Then you need a text box to tie all this too.  The search results will be shown under this text box to give the appearance of a dropdown.  This simple form should do:

<form action="/Search/ProcessTheForm" method="post">
    <input id="searchTerm" name="searchTerm" type="text" />
    <input type="submit" value="Go" />
</form>

Next, you'll need to use the autocomplete function in jQuery UI like this:

<script type="text/javascript">
    $(function () {
        $("#searchTerm").autocomplete({
            source: "/Search/AutocompleteSuggestions",
            minLength: 3,
            select: function (event, ui) {
                if (ui.item) {
                    $("#searchTerm").val(ui.item.value);
                    $("form").submit();
                }
            }
        });
    });
</script>

Here we've got a jQuery selector binding the autocomplete function to the searchTerm input box("#searchTerm").  We then set the URL for the source for the autocomplete suggestions, which in this case, will be our controller (Search) and action method (AutocompleteSuggestions).  Then we set the number of characters the user has to type before we make the first call.  It's set to three here to prevent pulling back meaningless matches from searching too soon.

Finally, we set up the autocomplete function's select event to set the selected value from the dropdown list as the value in the searchTerm input box and submit the form to the Search controller and the ProcessTheForm action method.

Here's the entire view for reference:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<!DOCTYPE html>
<html>
<head>
    <title>Autocomplete Test</title>
    <script src="<%: Url.Content("~/Scripts/jquery-1.4.4.min.js")%>" type="text/javascript"></script>
    <script src="<%: Url.Content("~/Scripts/jquery-ui.min.js")%>" type="text/javascript"></script>
</head>
<body>
    <form action="/Search/ProcessTheForm" method="post">
        <input id="searchTerm" name="searchTerm" type="text" />
        <input type="submit" value="Go" />
    </form>
    <script type="text/javascript">
        $(function () {
            $("#searchTerm").autocomplete({
                source: "/Search/AutocompleteSuggestions",
                minLength: 3,
                select: function (event, ui) {
                    if (ui.item) {
                        $("#searchTerm").val(ui.item.value);
                        $("form").submit();
                    }
                }
            });
        });
    </script>
</body>
</html>

The controller

Now you need to write something that will return the records that match what the user has entered so far.  This might be a database call with a LIKE searchTerm + "%" (watch out for SQL injection, though) or SOUNDEX or a web service call.  Be sure you limit your returned search results to maybe the top 10 matches so you don't bog things down with too much data moving over the wire.

Next, set up a controller action to invoke this back-end call and JSON up the returned list.  We've already names the controller (Search) and action (AutocompleteSuggestions) in our view.  Something like this should work, where _searchRepository is my repository call that finds matching strings, which are then converted to JSON:

public JsonResult AutocompleteSuggestions(string term)
{
    var suggestions = _searchRepository.GetAutoCompleteSearchSuggestion(term);
    return Json(suggestions, JsonRequestBehavior.AllowGet);
}

Don't forget the JsonRequestBehavior.AllowGet parameter in the Json call.  You won't get anything back from the action method if you leave it off.

Also, the name of the parameter passed into the action method is important.  The jQuery UI autocomplete method will call your source URL with a query string like "?term=foo".  If you set the parameter name to a string named "term", the MVC model binder will grab the value from the query string for you.

The jQuery UI Autocomplete function has several other options and events you can use in your app, and the demos are worth checking out too.

Tags: ,
Categories: Technical


kick it on DotNetKicks.com shout it on DotNetShoutOut

Image Details