SSRS: How to use a web service as a data source

Summary

Configuring SSRS to use an XML Data Source can be done with just a few steps. First, you add a shared data source that points to your web service. Second, you add a data set that defines the parameters for the web method. Once you have these defined you can build your report as normal. The only caveat I have found is the lack of strongly typed fields returned from the web service. You will need to cast each field appropriately within the report for grouping and formatting functions to work.

Instructions

Add Shared Data Source

  1. Right Click Shared Data Sources
  2. Choose Add New DataSource
  3. Give it a name and choose Type: XML
  4. Enter the path to the web service as the connection string
  5. Click OK

Add Data Set

  1. Right click Datasets
  2. Click Add Dataset...
  3. Enter a name
  4. Choose the name of your shared data source
  5. Enter the following query replacing WebMethodName and WebMethodParameter. Include as many parameters as necessary. Leave the tempuri.org as is.
    <Query>
        <SoapAction>http://tempuri.org/WebMethodName</SoapAction>
        <Method Namespace="http://tempuri.org/" Name="WebMethodName">
        <Parameters>
            <Parameter Name="WebMethodParameter"></Parameter>
        </Parameters>
        </Method>
        <ElementPath IgnoreNamespaces="true">*</ElementPath>
    </Query>
  6. Click Parameters
  7. Add each parameter required for your web service
  8. Click OK

Add the dataset to your report, cast all the fields, and you’re done!

ASP.NET MVC: How to make a working progress bar

As is, no warranty... (uses twitter bootstrap styles) Controller
public ActionResult Async()
{
    return View();
}

// Submit this page to begin processing
[AcceptVerbs(HttpVerbs.Post)]
public JsonResult Async(FormCollection collection)
{
    try
    {
        // some test data
        var records = new List();
        for (var i = 0; i < 10; i++)
            records.Add(i);

        // async storage (must be at app level?)
        HttpContext.Application["RecordsTotal"] = records.Count;
        HttpContext.Application["RecordsProcessed"] = 0;
        
        var caller = new AsyncProcessCaller(AsyncProcess);
        caller.BeginInvoke(records, null, null);

        return Json(new { Result = "Started..." }, JsonRequestBehavior.AllowGet);
    }
    catch (Exception ex)
    {
        return Json(new { Exception = ex.ToString() }, JsonRequestBehavior.AllowGet);
    }
}

// provide a signature for executing asynchronusly
public delegate void AsyncProcessCaller(List records);

// the actual method that does the work
public void AsyncProcess(List records)
{
    // do stuff with the records
    foreach (var record in records)
    {
        System.Threading.Thread.Sleep(1000); // pretend we did labor intesive work
        HttpContext.Application["RecordsProcessed"] = (int)HttpContext.Application["RecordsProcessed"] + 1;
    }
}

// a method that returns the status, call this with javascript to update your status bar
public JsonResult AsyncStatus()
{
    var total = (int)HttpContext.Application["RecordsTotal"];
    var processed = (int)HttpContext.Application["RecordsProcessed"];
    var percent = Math.Round(((decimal) processed / (decimal) total) * 100, 0);

    return Json(new { PercentComplete = percent }, JsonRequestBehavior.AllowGet);
}
HTML
<div class="progress progress-striped">
    <div class="bar" style="width: 0%;"></div>
</div>

<input type="button" class="btn btn-primary" value="Start!" onclick="start();"/>

<script type="text/javascript">
    
    // function to launch the mail process
    function start() {
        $.post('/Admin/Async', function (data) {
            if (data.Exception) {
                alert(data.Exception);
                return;
            } else {
                alert(data.Result);
                updateStatus();
            }
        });
    }
    
    // update the progress bar
    function updateStatus() {
        $.ajax({
            url: "/Admin/AsyncStatus",
            type: "GET",
            dataType: "json",
            success: function (data) {
                var percentComplete = parseInt(data.PercentComplete);
                if (percentComplete == null || percentComplete == 100) {
                    $(".progress").removeClass("active"); // we're done!
                    $(".progress .bar").css("width", "100%");
                } else { // update the progress bar
                    $(".progress").addClass("active");
                    $(".progress .bar").css("width", percentComplete + "%");
                    setTimeout(updateStatus, 1000); // call self to refresh
                }
            }
        });
    }
</script>

Visual Studio 2012: Customizing MVC 4 Code Generation Templates

  1. Copy the files from here:
    C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ItemTemplates\CSharp\Web\MVC 4\CodeTemplates
    To your project folder:
    - App Data
    - CodeTemplates
        - AddController
        - AddView
    - Content
    - Controllers
    - Etc...
    Global.asax
    Web.config
  2. (If you did a drag and drop into Visual Studio you'll have .cs files that are created by Visual Studio underneath the .tt files, they should be deleted
  3. Select all the .tt files
  4. Under Properties, change Build Action to "None" and Custom Tool to "" (blank)
Notes:
  • If you create a template with your own name, you will see it in the dropdown when you go to generate a view

Visual Studio 2012: Get rid of the white border around the selected line

To get rid of the white border around the selected line in the code window, go into Tools > Options > Expand Text Editor > Select General > Under Display > Uncheck "Highlight current line" Via Dennis Evans' comment on this post: Visual Studio 2012 RC is released - The Big Web Rollup

C#: How to check if a file is locked

I haven't tried this yet. Source
private static int _numberOfTries = 10;

private static int _timeIntervalBetweenTries = 500; // half second interval

private FileStream GetStream(FileAccess fileAccess, string filePath)
{
 var tries = 0;
 while (true)
 {
  try
  {
   return File.Open(filePath, FileMode.Open, fileAccess);
  }
  catch (IOException e)
  {
   if (!IsFileLocked(e))
    throw;
   if (++tries > _numberOfTries)
    throw new Exception("The file has been locked too long: " + e.Message, e);
   Thread.Sleep(_timeIntervalBetweenTries);
  }
 }
}

private static bool IsFileLocked(IOException exception)
{
 int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
 return errorCode == 32 || errorCode == 33;
}

Javascript: Format JSON Date

If you get something that looks like this from JSON:
/Date(1339439400000)/
You can format it like this:
var jsonDate = '/Date(1339439400000)/'; // raw date data
var jsDate = new Date(parseInt(jsonDate.substr(6))); // convert to date object
var result = $.format.date(jsDate,'MM/dd/yyyy'); // apply format
Using can find the jquery.format.1.x library here: http://www.asual.com/jquery/format

Entity Framework: Can't Add View

Problem:

You can't add a view to the designer.

Solution:

You need a unique, non-nullable column for the modal to work in Entity Framework. Example:

SELECT [RowNumber] = ISNULL(CONVERT(INT, ROW_NUMBER() OVER (ORDER BY Column1)), 0), Column1, Column2...
FROM [TableName] 
Notes:

You may also get errors if you try to add a view to the designer manually, including:

  • EntityType '(EntityName)' has no key defined. Define the key for this EntityType.
  • "No mapping specified for the following EntitySet/AssociationSet - (EntityName)".
But don't bother trying to fix them. Using the above method should work in most instances.