<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Adventures in Software</title>
	<link>http://adventuresinsoftware.com/blog</link>
	<description>Lessons learned on the road to quality computing</description>
	<pubDate>Thu, 09 Sep 2010 18:00:05 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>Entity Framework and the Repository Pattern</title>
		<link>http://adventuresinsoftware.com/blog/?p=550</link>
		<comments>http://adventuresinsoftware.com/blog/?p=550#comments</comments>
		<pubDate>Thu, 09 Sep 2010 17:55:48 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[DDD]]></category>

		<category><![CDATA[Entity Framework]]></category>

		<category><![CDATA[Unit testing]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=550</guid>
		<description><![CDATA[When I’ve asked how to unit test Entity Framework, the best answer was “use the Repository pattern to encapsulate your EF code” (thanks Andrew Peters). I recently asked the same thing about RIA Services. Mike Brown responded with the same advice, even going so far as to spend a couple of hours with me on [...]]]></description>
			<content:encoded><![CDATA[<p>When I’ve asked <a href="http://stackoverflow.com/questions/575190/is-there-an-in-memory-provider-for-entity-framework">how to unit test Entity Framework</a>, the best answer was “use the Repository pattern to encapsulate your EF code” (thanks <a href="http://andrewpeters.net/">Andrew Peters</a>). I recently asked the same thing about RIA Services. <a href="http://azurecoding.net/blogs/brownie/">Mike Brown</a> responded with the same advice, even going so far as to spend a couple of hours with me on Live Meeting.</p>
<p>Since <strong>all you gotta do is</strong> implement the Repository Pattern, it should be easy, right? Let’s take a look at a minimalist implementation.</p>
<h3>Inject the implementation</h3>
<p>To support unit testing, we need to be able to swap out our implementation. At the top level, the consumer of a repository begins a unit of work. So we’ll inject a unit of work factory.</p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">IUnitOfWorkFactory
</span>{
    <span style="color: #2b91af">IUnitOfWork </span>Begin();
}</pre>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">NoteworthyService
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">IUnitOfWorkFactory </span>_unitOfWorkFactory;

    <span style="color: blue">public </span>NoteworthyService(<span style="color: #2b91af">IUnitOfWorkFactory </span>unitOfWorkFactory)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
    }
}</pre>
<h3>Identify the repository</h3>
<p>In DDD we create one repository per aggregate root, which is the entity from which you begin the query. In EF, entities exist in a container. So we’ll take two steps to get the repository via the container.</p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">IUnitOfWork </span>: <span style="color: #2b91af">IDisposable
</span>{
    <span style="color: #2b91af">IContainer</span>&lt;TContainer&gt; UsingContainer&lt;TContainer&gt;()
        <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>();
}

<span style="color: blue">public interface </span><span style="color: #2b91af">IContainer</span>&lt;TContainer&gt; : <span style="color: #2b91af">IDisposable
</span>{
    <span style="color: #2b91af">IRepository</span>&lt;TEntity&gt; GetRepository&lt;TEntity&gt;(<span style="color: #2b91af">Func</span>&lt;TContainer, <span style="color: #2b91af">ObjectQuery</span>&lt;TEntity&gt;&gt; repositorySelector)
        <span style="color: blue">where </span>TEntity : <span style="color: #2b91af">EntityObject</span>;
}</pre>
<h3>Provide a specification</h3>
<p>The second half of the Repository Pattern is the Specification. A specification identifies which entities to pull from the repository. In Linq, we use lambdas for that. So a repository should be able to give you back some entities when given a lambda.</p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">IRepository</span>&lt;TEntity&gt;
{
    <span style="color: #2b91af">IQueryable</span>&lt;TEntity&gt; GetSatisfying(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;TEntity, <span style="color: blue">bool</span>&gt;&gt; specification);
    <span style="color: blue">void </span>Add(TEntity entity);
}</pre>
<h3>Query the repository</h3>
<p>With those interfaces in place, here’s what a query looks like.</p>
<pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Article</span>&gt; GetArticlesByTopic(<span style="color: blue">string </span>topicName)
{
    <span style="color: blue">using </span>(<span style="color: blue">var </span>unitOfWork = _unitOfWorkFactory.Begin())
    {
        <span style="color: blue">return </span>unitOfWork.UsingContainer&lt;<span style="color: #2b91af">NoteworthyEntities</span>&gt;().GetRepository(container =&gt; container.Articles)
            .GetSatisfying(article =&gt; article.Topics.Any(topic =&gt; topic.TopicName == topicName))
            .ToList();
    }
}</pre>
<h3>Implement in memory</h3>
<p>For unit testing, we implement the repository interfaces using in-memory lists.</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">MemoryUnitOfWorkFactory </span>: <span style="color: #2b91af">IUnitOfWorkFactory
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">MemoryUnitOfWork </span>_unitOfWork = <span style="color: blue">new </span><span style="color: #2b91af">MemoryUnitOfWork</span>();

    <span style="color: blue">public </span><span style="color: #2b91af">IUnitOfWork </span>Begin()
    {
        <span style="color: blue">return </span>_unitOfWork;
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">MemoryUnitOfWork </span>: <span style="color: #2b91af">IUnitOfWork
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: blue">object</span>&gt; _containerByType = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: blue">object</span>&gt;();

    <span style="color: blue">public </span><span style="color: #2b91af">IContainer</span>&lt;TContainer&gt; UsingContainer&lt;TContainer&gt;()
        <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>()
    {
        <span style="color: blue">object </span>container;
        <span style="color: blue">if </span>(!_containerByType.TryGetValue(<span style="color: blue">typeof</span>(TContainer), <span style="color: blue">out </span>container))
        {
            container = <span style="color: blue">new </span><span style="color: #2b91af">MemoryContainer</span>&lt;TContainer&gt;();
            _containerByType.Add(<span style="color: blue">typeof</span>(TContainer), container);
        }
        <span style="color: blue">return </span>(<span style="color: #2b91af">IContainer</span>&lt;TContainer&gt;)container;
    }

    <span style="color: blue">public void </span>Dispose()
    {
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">MemoryContainer</span>&lt;TContainer&gt; : <span style="color: #2b91af">IContainer</span>&lt;TContainer&gt;
    <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>()
{
    <span style="color: blue">private </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: blue">object</span>&gt; _containerByType = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: blue">object</span>&gt;();

    <span style="color: blue">public </span><span style="color: #2b91af">IRepository</span>&lt;TEntity&gt; GetRepository&lt;TEntity&gt;(<span style="color: #2b91af">Func</span>&lt;TContainer, <span style="color: #2b91af">ObjectQuery</span>&lt;TEntity&gt;&gt; repositorySelector)
        <span style="color: blue">where </span>TEntity : <span style="color: #2b91af">EntityObject
    </span>{
        <span style="color: blue">object </span>container;
        <span style="color: blue">if </span>(!_containerByType.TryGetValue(<span style="color: blue">typeof</span>(TEntity), <span style="color: blue">out </span>container))
        {
            container = <span style="color: blue">new </span><span style="color: #2b91af">MemoryRepository</span>&lt;TEntity&gt;();
            _containerByType.Add(<span style="color: blue">typeof</span>(TEntity), container);
        }
        <span style="color: blue">return </span>(<span style="color: #2b91af">IRepository</span>&lt;TEntity&gt;)container;
    }

    <span style="color: blue">public void </span>Dispose()
    {
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">MemoryRepository</span>&lt;TEntity&gt; : <span style="color: #2b91af">IRepository</span>&lt;TEntity&gt;
    <span style="color: blue">where </span>TEntity : <span style="color: #2b91af">EntityObject
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">List</span>&lt;TEntity&gt; _entities = <span style="color: blue">new </span><span style="color: #2b91af">List</span>&lt;TEntity&gt;();

    <span style="color: blue">public </span><span style="color: #2b91af">IQueryable</span>&lt;TEntity&gt; GetSatisfying(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;TEntity, <span style="color: blue">bool</span>&gt;&gt; specification)
    {
        <span style="color: blue">return </span>_entities.Where(specification.Compile()).AsQueryable();
    }

    <span style="color: blue">public void </span>Add(TEntity entity)
    {
        _entities.Add(entity);
    }
}</pre>
<p>And here’s what a unit test looks like.</p>
<pre class="code">[<span style="color: #2b91af">TestClass</span>]
<span style="color: blue">public class </span><span style="color: #2b91af">NoteworthyServiceTest
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">NoteworthyService </span>_noteworthyService;

    [<span style="color: #2b91af">TestInitialize</span>]
    <span style="color: blue">public void </span>Initialize()
    {
        <span style="color: #2b91af">IUnitOfWorkFactory </span>memory = <span style="color: blue">new </span><span style="color: #2b91af">MemoryUnitOfWorkFactory</span>();

        <span style="color: #2b91af">IRepository</span>&lt;<span style="color: #2b91af">Article</span>&gt; articlesRepository = memory.Begin()
            .UsingContainer&lt;<span style="color: #2b91af">NoteworthyEntities</span>&gt;()
            .GetRepository(container =&gt; container.Articles);
        <span style="color: #2b91af">Topic </span>ddd = <span style="color: blue">new </span><span style="color: #2b91af">Topic</span>()
        {
            TopicName = <span style="color: #a31515">&quot;ddd&quot;
        </span>};
        <span style="color: #2b91af">Topic </span>corresopndence = <span style="color: blue">new </span><span style="color: #2b91af">Topic</span>()
        {
            TopicName = <span style="color: #a31515">&quot;correspondence&quot;
        </span>};
        <span style="color: #2b91af">Article </span>efRepository = <span style="color: blue">new </span><span style="color: #2b91af">Article</span>()
        {
            Title = <span style="color: #a31515">&quot;Entity Framework and the Repository Pattern&quot;
        </span>};
        efRepository.Topics.Add(ddd);
        <span style="color: #2b91af">Article </span>correspondenceLaunch = <span style="color: blue">new </span><span style="color: #2b91af">Article</span>()
        {
            Title = <span style="color: #a31515">&quot;Correspondence Launch&quot;
        </span>};
        correspondenceLaunch.Topics.Add(corresopndence);
        <span style="color: #2b91af">Article </span>correspondenceDDD = <span style="color: blue">new </span><span style="color: #2b91af">Article</span>()
        {
            Title = <span style="color: #a31515">&quot;Correspondence and DDD&quot;
        </span>};
        correspondenceDDD.Topics.Add(ddd);
        correspondenceDDD.Topics.Add(corresopndence);

        articlesRepository.Add(efRepository);
        articlesRepository.Add(correspondenceLaunch);
        articlesRepository.Add(correspondenceDDD);

        _noteworthyService = <span style="color: blue">new </span><span style="color: #2b91af">NoteworthyService</span>(memory);
    }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>QueryReturnsArticles()
    {
        <span style="color: blue">var </span>articles = _noteworthyService.GetArticlesByTopic(<span style="color: #a31515">&quot;ddd&quot;</span>).ToArray();

        <span style="color: #2b91af">Assert</span>.AreEqual(<span style="color: #a31515">&quot;Entity Framework and the Repository Pattern&quot;</span>, articles[0].Title);
        <span style="color: #2b91af">Assert</span>.AreEqual(<span style="color: #a31515">&quot;Correspondence and DDD&quot;</span>, articles[1].Title);
    }
}</pre>
<h3>Implement with Entity Framework</h3>
<p>Finally, we implement the real thing using Entity Framework.</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">EntityFrameworkUnitOfWorkFactory </span>: <span style="color: #2b91af">IUnitOfWorkFactory
</span>{
    <span style="color: blue">public </span><span style="color: #2b91af">IUnitOfWork </span>Begin()
    {
        <span style="color: blue">return new </span><span style="color: #2b91af">EntityFrameworkUnitOfWork</span>();
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">EntityFrameworkUnitOfWork </span>: <span style="color: #2b91af">IUnitOfWork
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: #2b91af">IDisposable</span>&gt; _containerByType = <span style="color: blue">new </span><span style="color: #2b91af">Dictionary</span>&lt;<span style="color: #2b91af">Type</span>, <span style="color: #2b91af">IDisposable</span>&gt;();

    <span style="color: blue">public </span><span style="color: #2b91af">IContainer</span>&lt;TContainer&gt; UsingContainer&lt;TContainer&gt;()
        <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>()
    {
        <span style="color: #2b91af">IDisposable </span>container;
        <span style="color: blue">if </span>(!_containerByType.TryGetValue(<span style="color: blue">typeof</span>(TContainer), <span style="color: blue">out </span>container))
        {
            container = <span style="color: blue">new </span><span style="color: #2b91af">EntityFrameworkContainer</span>&lt;TContainer&gt;();
            _containerByType.Add(<span style="color: blue">typeof</span>(TContainer), container);
        }
        <span style="color: blue">return </span>(<span style="color: #2b91af">IContainer</span>&lt;TContainer&gt;)container;
    }

    <span style="color: blue">public void </span>Dispose()
    {
        <span style="color: blue">foreach </span>(<span style="color: blue">var </span>container <span style="color: blue">in </span>_containerByType.Values)
            container.Dispose();
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">EntityFrameworkContainer</span>&lt;TContainer&gt; : <span style="color: #2b91af">IContainer</span>&lt;TContainer&gt;
    <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>()
{
    <span style="color: blue">private </span>TContainer _container;

    <span style="color: blue">public </span>EntityFrameworkContainer()
    {
        _container = <span style="color: blue">new </span>TContainer();
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IRepository</span>&lt;TEntity&gt; GetRepository&lt;TEntity&gt;(<span style="color: #2b91af">Func</span>&lt;TContainer, <span style="color: #2b91af">ObjectQuery</span>&lt;TEntity&gt;&gt; repositorySelector)
        <span style="color: blue">where </span>TEntity : <span style="color: #2b91af">EntityObject
    </span>{
        <span style="color: blue">return new </span><span style="color: #2b91af">EntityFrameworkRepository</span>&lt;TContainer, TEntity&gt;(_container, repositorySelector(_container));
    }

    <span style="color: blue">public void </span>Dispose()
    {
        _container.Dispose();
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">EntityFrameworkRepository</span>&lt;TContainer, TEntity&gt; : <span style="color: #2b91af">IRepository</span>&lt;TEntity&gt;
    <span style="color: blue">where </span>TContainer : <span style="color: #2b91af">ObjectContext</span>, <span style="color: blue">new</span>()
    <span style="color: blue">where </span>TEntity : <span style="color: #2b91af">EntityObject
</span>{
    <span style="color: blue">private </span>TContainer _container;
    <span style="color: blue">private </span><span style="color: #2b91af">ObjectQuery</span>&lt;TEntity&gt; _objectQuery;

    <span style="color: blue">public </span>EntityFrameworkRepository(TContainer container, <span style="color: #2b91af">ObjectQuery</span>&lt;TEntity&gt; objectQuery)
    {
        _container = container;
        _objectQuery = objectQuery;
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IQueryable</span>&lt;TEntity&gt; GetSatisfying(<span style="color: #2b91af">Expression</span>&lt;<span style="color: #2b91af">Func</span>&lt;TEntity, <span style="color: blue">bool</span>&gt;&gt; specification)
    {
        <span style="color: blue">return </span>_objectQuery.Where(specification);
    }

    <span style="color: blue">public void </span>Add(TEntity entity)
    {
        _container.AddObject(_objectQuery.Name, entity);
    }
}</pre>
<h3>Analysis</h3>
<p>This is the smallest implementation of the Repository pattern that I could come up with. It is obviously not feature complete. For example, it does not implement Delete, nor does it allow you to specify eager loading with Include. There are <a href="http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx">other implementations that are bigger</a>, but I doubt that there could be one smaller. Even at this size, this doesn’t qualify as “all you need to do is”.</p>
<p>One benefit of the Repository pattern is supposed to be that it abstracts the persistence mechanism. But this implementation returns EntityObjects, which are a distinctly Entity Framework-ish data type. I could try for a POCO compliant implementation to solve that problem.</p>
<p>Because this implementation requires EntityObjects, it could never work with RIA Services. I would have to write a different Repository implementation to unit test my client code.</p>
<p>And finally, Entity Framework does some things that the in-memory repository does not. My unit tests can’t verify that I’m using EF correctly. For example, Entity Framework does eager loading if I explicitly request it. The in-memory implementation always has all navigation properties populated. Because of this difference, I can’t verify with a unit test that I have included all of the required navigations.</p>
<h3>Conclusion</h3>
<p>All of this leads me to conclude that the Repository pattern is not the best way to add testability to an untestable framework. The framework needs to be testable from the beginning. If Entity Framework had provided an in-memory implementation for testing, then I could test <em>my use of</em> EF, including eager loading.</p>
<p>By the way, <a href="http://correspondence.codeplex.com">Correspondence</a> does in fact provide an in-memory implementation for unit testing. Please go through the lessons to see what I think a testable framework should look like.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=550</wfw:commentRss>
		</item>
		<item>
		<title>Pass context parameters to SSRS reports in a web application</title>
		<link>http://adventuresinsoftware.com/blog/?p=549</link>
		<comments>http://adventuresinsoftware.com/blog/?p=549#comments</comments>
		<pubDate>Tue, 07 Sep 2010 20:58:12 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=549</guid>
		<description><![CDATA[When viewing reports within an application, the application can provide context that SSRS otherwise would not have. With this context the experience of using the application can be better than the report manager. Parameters that the user would otherwise have to set for every report can be assigned programmatically.
In my case, the logged-in user belongs [...]]]></description>
			<content:encoded><![CDATA[<p>When <a href="http://adventuresinsoftware.com/blog/?p=547">viewing reports within an application</a>, the application can provide context that SSRS otherwise would not have. With this context the experience of using the application can be better than the report manager. Parameters that the user would otherwise have to set for every report can be assigned programmatically.</p>
<p>In my case, the logged-in user belongs to a medical practice. Every report takes the practice ID as a parameter, called “Domain”. I want to pass that parameter without the user ever seeing it.</p>
<h3>Render the menu</h3>
<p>Earlier, we wrote code to <a href="http://adventuresinsoftware.com/blog/?p=542">navigate the reports</a>. Let’s display this structure in a hierarchy.</p>
<pre class="code"><span style="color: blue">public string </span>GetMenu()
{
    <span style="color: #2b91af">StringBuilder </span>result = <span style="color: blue">new </span><span style="color: #2b91af">StringBuilder</span>();
    WriteItems(result, <span style="color: #2b91af">ReportNavigator</span>.GetRootFolder(_credentials).Items);
    <span style="color: blue">return </span>result.ToString();
}

<span style="color: blue">private static void </span>WriteItems(<span style="color: #2b91af">StringBuilder </span>result, <span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">Item</span>&gt; items)
{
    <span style="color: blue">foreach </span>(<span style="color: #2b91af">Item </span>item <span style="color: blue">in </span>items)
    {
        <span style="color: #2b91af">Folder </span>subFolder = item <span style="color: blue">as </span><span style="color: #2b91af">Folder</span>;
        <span style="color: blue">if </span>(subFolder != <span style="color: blue">null</span>)
        {
            WriteFolder(result, subFolder);
            <span style="color: blue">continue</span>;
        }

        <span style="color: #2b91af">Report </span>report = item <span style="color: blue">as </span><span style="color: #2b91af">Report</span>;
        <span style="color: blue">if </span>(report != <span style="color: blue">null</span>)
        {
            WriteReport(result, report);
            <span style="color: blue">continue</span>;
        }
    }
}

<span style="color: blue">private static void </span>WriteFolder(<span style="color: #2b91af">StringBuilder </span>result, <span style="color: #2b91af">Folder </span>folder)
{
    <span style="color: blue">if </span>(folder.ContainsAnyReport)
    {
        result.Append(<span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">&quot;&lt;li class=\&quot;folder\&quot;&gt;{0}: {1}&lt;ul&gt;&quot;</span>,
            <span style="color: #2b91af">HttpUtility</span>.HtmlEncode(folder.Name),
            <span style="color: #2b91af">HttpUtility</span>.HtmlEncode(folder.Description)));
        WriteItems(result, folder.Items);
        result.Append(<span style="color: #a31515">&quot;&lt;/ul&gt;&lt;/li&gt;&quot;</span>);
    }
}

<span style="color: blue">private static void </span>WriteReport(<span style="color: #2b91af">StringBuilder </span>result, <span style="color: #2b91af">Report </span>report)
{
    result.Append(<span style="color: #2b91af">String</span>.Format(<span style="color: #a31515">&quot;&lt;li class=\&quot;report\&quot;&gt;&lt;a href=\&quot;ViewReport.aspx?Path={1}\&quot;&gt;{0}: {2}&lt;/a&gt;&lt;/li&gt;&quot;</span>,
        <span style="color: #2b91af">HttpUtility</span>.HtmlEncode(report.Name),
        <span style="color: #2b91af">HttpUtility</span>.UrlEncode(report.Path),
        <span style="color: #2b91af">HttpUtility</span>.HtmlEncode(report.Description)));
}</pre>
<p>This mutually-recursive set of methods renders a tree of unordered lists. It shows only the folders that contain a report. When it gets down to a report, it renders a link to the ViewReport page. This is our page containing a report viewer control.</p>
<h3>Display the report</h3>
<p>The ViewReport page simply contains a report viewer control. Page_Load sets the path, the <a href="http://adventuresinsoftware.com/blog/?p=539">credentials</a>, and the Domain parameter.</p>
<pre class="code"><span style="color: blue">protected void </span>Page_Load(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
    _path = Request[<span style="color: #a31515">&quot;Path&quot;</span>];

    <span style="color: blue">if </span>(Request.HttpMethod == <span style="color: #a31515">&quot;GET&quot; </span>&amp;&amp; !<span style="color: blue">string</span>.IsNullOrEmpty(_path))
    {
        ReportViewer1.ServerReport.ReportPath = _path;
        _reportTitle = _path.Split(<span style="color: #a31515">'/'</span>).LastOrDefault();

        <span style="color: green">// MLP: Get the user's credentials from forms auth.
        </span><span style="color: #2b91af">IIdentity </span>identity = <span style="color: #2b91af">HttpContext</span>.Current.User.Identity;
        <span style="color: #2b91af">FormsIdentity </span>formsIdentity = (<span style="color: #2b91af">FormsIdentity</span>)identity;
        <span style="color: blue">string </span>username = formsIdentity.Name;
        <span style="color: blue">string </span>encryptedPassword = formsIdentity.Ticket.UserData;

        <span style="color: green">// MLP: Decrypt the password.
        </span><span style="color: blue">byte</span>[] usernameHash = <span style="color: #2b91af">Crypto</span>.ComputeStringHash(username, _hashAlgorith);
        <span style="color: blue">byte</span>[] encryptedMessage = <span style="color: #2b91af">Convert</span>.FromBase64String(encryptedPassword);
        <span style="color: blue">string </span>password = <span style="color: #2b91af">Crypto</span>.DecryptMessage(encryptedMessage, _symmetricAlgorithm, _key, usernameHash);

        <span style="color: #2b91af">NetworkReportServerCredentials </span>credentials = <span style="color: blue">new </span><span style="color: #2b91af">NetworkReportServerCredentials</span>(username, password, <span style="color: #a31515">&quot;ABSG&quot;</span>);
        ReportViewer1.ServerReport.ReportServerCredentials = credentials;

        <span style="color: blue">string </span>domain = GetDomainOfUser(username);
        <span style="color: #2b91af">ReportParameterInfoCollection </span>parameters = ReportViewer1.ServerReport.GetParameters();
        <span style="color: blue">if </span>(parameters.Any(p =&gt; p.Name == <span style="color: #a31515">&quot;Domain&quot; </span>&amp;&amp; p.DataType == <span style="color: #2b91af">ParameterDataType</span>.String))
            ReportViewer1.ServerReport.SetParameters(<span style="color: blue">new </span><span style="color: #2b91af">ReportParameter</span>(<span style="color: #a31515">&quot;Domain&quot;</span>, domain, <span style="color: blue"><strong>false</strong></span>));
    }
}</pre>
<p>The app looks up the domain based on the user name. Then it checks the parameters to see if this report accepts “Domain”. If so, it sets it.</p>
<p>The “false” in the ReportParameter tells the report viewer to hide the parameter from the user. If it were “true”, the user would still see the parameter, even though it was set to a default value.</p>
<p>Now my business administrators can create any report they need in SSRS report manager. Their report will appear on the menu automatically. If they follow the convention and specify a “Domain” parameter, the report will be context sensitive. This gives the end user of my application be best experience possible.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=549</wfw:commentRss>
		</item>
		<item>
		<title>Drupal Argument #2 should be an array in system.module on line 1015</title>
		<link>http://adventuresinsoftware.com/blog/?p=548</link>
		<comments>http://adventuresinsoftware.com/blog/?p=548#comments</comments>
		<pubDate>Mon, 06 Sep 2010 18:48:10 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Drupal]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=548</guid>
		<description><![CDATA[If you update Drupal or one of its modules and you get the following error on a white page with no style:
warning: array_map() [function.array-map]: Argument #2 should be an array in system.module on line 1015

It means that your theme is no longer enabled.
I updated Drupal using the instructions Upgrading Drupal rapidly using SSH/Shell commands. This [...]]]></description>
			<content:encoded><![CDATA[<p>If you update Drupal or one of its modules and you get the following error on a white page with no style:</p>
<blockquote><p>warning: array_map() [function.array-map]: Argument #2 should be an array in system.module on line 1015</p>
</blockquote>
<p>It means that your theme is no longer enabled.</p>
<p>I updated Drupal using the instructions <a href="http://drupal.org/node/297496">Upgrading Drupal rapidly using SSH/Shell commands</a>. This is an excellent resource. Take the time to follow all of the steps, including making backups! It’s the backup that allowed me to quickly resolve the issue.</p>
<p>The instructions preserve the sites folder, but not the themes folder. I created a custom theme for my wife’s blog. When upgrading Drupal, this custom theme was backed up, but not applied to the new installation.</p>
<p>The discussion on this <a href="http://drupal.org/node/696184">issue report</a> led me to look at the Themes admin page, where I discovered that the custom theme was no longer listed. I copied the theme from the backup (cp -r d-backup/themes/mtheme/ themes/) and refreshed the page. The theme was listed, but not enabled. I enabled it, set it to the default, and checked the site again. The issue was resolved.</p>
<p>Overall, I like Drupal. But it suffers from its PHP foundation. In general, it does a good job of abstracting the user from the PHP underpinnings, but when it breaks, it breaks hard.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=548</wfw:commentRss>
		</item>
		<item>
		<title>Navigating SSRS reports in prior versions of SQL Server</title>
		<link>http://adventuresinsoftware.com/blog/?p=547</link>
		<comments>http://adventuresinsoftware.com/blog/?p=547#comments</comments>
		<pubDate>Fri, 27 Aug 2010 21:41:54 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=547</guid>
		<description><![CDATA[Recently, I created an application that navigates SSRS reports. I’m developing against SQL 2008 R2, so my instructions were specific to that platform.
If you are not yet on R2, you can still develop such an application. Here’s what you’ll need to do differently.
Use the ReportService2005.asmx endpoint    In my example, I used the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I created an application that <a href="http://adventuresinsoftware.com/blog/?p=542">navigates SSRS reports</a>. I’m developing against SQL 2008 R2, so my instructions were specific to that platform.</p>
<p>If you are not yet on R2, you can still develop such an application. Here’s what you’ll need to do differently.</p>
<p><strong>Use the ReportService2005.asmx endpoint</strong>    <br />In my example, I used the ReportService2010.asmx endpoint to access report service methods. If you are not on R2, that will give you the error:</p>
<blockquote><p>The path of the item 'wsdl' is not valid.</p>
</blockquote>
<p>You might try ReportService2006.asmx. But if you do, you will probably run up against this:</p>
<blockquote><p>This operation is not supported on a report server that runs in native mode</p>
</blockquote>
<p>The answer (thank you <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlreportingservices/thread/8a40f90f-60e5-4130-984f-dc42032376d4">Tristan Fernando</a>) is to use ReportService2005.asmx. Follow the instructions in my previous post, but replace the endpoint.</p>
<p><strong>Use the Type enum to identify catalog items     <br /></strong>My previous example used the TypeName string property to differentiate between folders and reports. ReportService2005.asmx uses an enum property called Type instead. Enums are safer than magic strings anyway.</p>
<p><strong>Don’t use DefaultCredentials</strong>    <br />This change is not related to R2. It’s just something I got wrong at first. If you are using Forms authentication, like I am, then DefaultCredentials won’t work for you. I set ReportingService2010.Credentials to CredentialCache.DefaultCredentials in my last example. It worked for me only because the app happened to be running under my own account.</p>
<p>Instead, create a NetworkCredential using the password that you captured during login. Use the code from <a href="http://adventuresinsoftware.com/blog/?p=539">Forward network credentials to Report Server</a> to capture and encrypt the password.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=547</wfw:commentRss>
		</item>
		<item>
		<title>Java Tuple update</title>
		<link>http://adventuresinsoftware.com/blog/?p=546</link>
		<comments>http://adventuresinsoftware.com/blog/?p=546#comments</comments>
		<pubDate>Fri, 20 Aug 2010 19:15:48 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=546</guid>
		<description><![CDATA[Download:

Jar file
Source code (from GitHub)
import com.mallardsoft.tuple

Four years ago I created a Java Tuple class. I needed a way to quickly create type-safe multi-valued keys in Java. Here’s what I came up with:
Map&#60;Pair&#60;String, String&#62;, Integer&#62; population = new HashMap&#60;Pair&#60;String, String&#62;, Integer&#62;();
population.put(
    Tuple.from(&#34;TX&#34;, &#34;Dallas&#34;),
    1213825);
population.put(
    Tuple.from(&#34;TX&#34;, &#34;Fort Worth&#34;),
 [...]]]></description>
			<content:encoded><![CDATA[<p>Download:</p>
<ul>
<li><a href="http://adventuresinsoftware.com/bin/tuple-1.1.jar">Jar file</a></li>
<li><a href="http://github.com/mallardsoft/tuple">Source code (from GitHub)</a></li>
<li>import com.mallardsoft.tuple</li>
</ul>
<p>Four years ago I created a Java Tuple class. I needed a way to quickly create type-safe multi-valued keys in Java. Here’s what I came up with:</p>
<pre>Map&lt;Pair&lt;String, String&gt;, Integer&gt; population = <span style="color: blue">new</span> HashMap&lt;Pair&lt;String, String&gt;, Integer&gt;();
population.put(
    Tuple.from(<span style="color: maroon">&quot;TX&quot;</span>, <span style="color: maroon">&quot;Dallas&quot;</span>),
    <span style="color: maroon">1213825</span>);
population.put(
    Tuple.from(<span style="color: maroon">&quot;TX&quot;</span>, <span style="color: maroon">&quot;Fort Worth&quot;</span>),
    <span style="color: maroon">624067</span>);
population.put(
    Tuple.from(<span style="color: maroon">&quot;IL&quot;</span>, <span style="color: maroon">&quot;Springfield&quot;</span>),
    <span style="color: maroon">203564</span>);
population.put(
    Tuple.from(<span style="color: maroon">&quot;NM&quot;</span>, <span style="color: maroon">&quot;Albuquerque&quot;</span>),
    <span style="color: maroon">494236</span>);

<span style="color: blue">int</span> p = population.get(
    Tuple.from(<span style="color: maroon">&quot;TX&quot;</span>, <span style="color: maroon">&quot;Fort Worth&quot;</span>));
<span style="color: green">// p = 624067</span>
assertEquals(<span style="color: maroon">624067</span>, p);
assertNull(population.get(
    Tuple.from(<span style="color: maroon">&quot;NM&quot;</span>, <span style="color: maroon">&quot;Roswell&quot;</span>)));
assertNull(population.get(
    Tuple.from(<span style="color: maroon">&quot;NJ&quot;</span>, <span style="color: maroon">&quot;Springfield&quot;</span>)));</pre>
<p>Tuple.from() creates a type-safe object containing the listed values. It implements equals(), getHashCode(), compareTo(), and toString() in meaningful ways. And it provides for multi-valued returns.</p>
<pre>Variable&lt;Boolean&gt; found = <span style="color: blue">new</span> Variable&lt;Boolean&gt;();
Variable&lt;Integer&gt; index = <span style="color: blue">new</span> Variable&lt;Integer&gt;();

findCharacter(<span style="color: maroon">&quot;Hello, world&quot;</span>, <span style="color: maroon">'w'</span>).extract(found).extract(index);
assertTrue(found.get());
<span style="color: blue">if</span> (found.get()) {
    <span style="color: blue">int</span> i = index.get();
    assertEquals(<span style="color: maroon">7</span>, i);
}
<span style="color: blue">else</span> {
    fail();
}</pre>
<p>Where findCharacter returns Pair&lt;Boolean, Integer&gt;. I <a href="http://adventuresinsoftware.com/blog/?p=43">published the source</a> and got a few comments.</p>
<p>The most persistent complaint was that Tuple only worked with types that implemented IComparable&lt;Themselves&gt;. This constraint was only used in compareTo(). If you wanted tuples for one of the other methods, you ran into a meaningless compiler issue.</p>
<p>I have since removed that generic constraint. Now you can create tuples of non-comparable types. If you try to compare them, you will get a run time issue.</p>
<p>If you have used this library in the past, or if you need tuples in Java, please download the latest using the links at the top of this article.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=546</wfw:commentRss>
		</item>
		<item>
		<title>Correspondence launch</title>
		<link>http://adventuresinsoftware.com/blog/?p=545</link>
		<comments>http://adventuresinsoftware.com/blog/?p=545#comments</comments>
		<pubDate>Wed, 04 Aug 2010 01:22:07 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Correspondence]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=545</guid>
		<description><![CDATA[ 
Download the project from Codeplex.
Correspondence is a library for building occasionally connected client applications. In other words, an app that can tolerate being off line. These have typically been hard to write. Correspondence makes it easier. It gives you the following features:

Client-side storage 
Server-side storage 
Client-server communication 
Client-to-client collaboration 

And because it’s based on [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/08/image.png"><img style="border-right-width: 0px; margin: 0px 0px 0px 5px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/08/image-thumb.png" width="644" height="324" /></a> </p>
<p><a href="http://correspondence.codeplex.com/">Download the project from Codeplex.</a></p>
<p>Correspondence is a library for building occasionally connected client applications. In other words, an app that can tolerate being off line. These have typically been hard to write. Correspondence makes it easier. It gives you the following features:</p>
<ul>
<li>Client-side storage </li>
<li>Server-side storage </li>
<li>Client-server communication </li>
<li>Client-to-client collaboration </li>
</ul>
<p>And because it’s based on Update Controls, you also get:</p>
<ul>
<li>Automatic dependency management </li>
<li>UI update notification </li>
<li>MVVM support </li>
</ul>
<p>So imagine that you and a friend are using the same application. They make a change. Your UI is updated. That’s what Correspondence does.</p>
<p><strong>The Factual modeling language</strong>     <br />To get all of these features, you have to model your data differently. You declare your model using a language called Factual. Here’s a snippet of Factual describing players and moves in a Reversi game:</p>
<pre><span style="color: blue">fact</span> <span style="color: #2b91af">Player</span> {
    <span style="color: blue">pivot</span> <span style="color: #2b91af">User</span> user;
    <span style="color: blue">pivot</span> <span style="color: #2b91af">Game</span> game;
    <span style="color: blue">int</span> index;

    <span style="color: #2b91af">Move</span>* moves {
        <span style="color: #2b91af">Move</span> m : m.player = <span style="color: blue">this</span>
    }

    <span style="color: blue">bool</span> isActive {
        <span style="color: blue">not</span> <span style="color: blue">exists</span> <span style="color: #2b91af">Outcome</span> o : o.game = <span style="color: blue">this</span>.game
    }
}

<span style="color: blue">fact</span> <span style="color: #2b91af">Move</span> {
    <span style="color: #2b91af">Player</span> player;
    <span style="color: blue">int</span> index;
    <span style="color: blue">int</span> square;
}</pre>
<p>The model is neither relational, nor object oriented. It is historical. It defines historical facts. These facts have fields, relationships, queries, and predicates. All of that is defined in the model so that Correspondence can generate the storage and communications for you. </p>
<p><strong>The development tools</strong> </p>
<p>When you get the Correspondence bits, you will pull down two installs. The first is for your development machine. It installs:</p>
<ul>
<li>The library assemblies </li>
<li>The Factual compiler </li>
<li>Project templates </li>
</ul>
<p>Once you install this component, you’ll want to go into Visual Studio and hit “File”, “New”, “Visual C#”, “Correspondence”, “Correspondence Model”. This will create a project that references the right assemblies, and has a T4 template that runs the Factual compiler. Using the other project templates, you can create view models, unit tests, and WPF applications that use that model.</p>
<p><strong>SyncExpress</strong> </p>
<p>The second install is for your server. It installs a Windows service called “Correspondence SyncExpress”. It runs on http://localhost:9119/SyncExpress. Point your clients at that service and they will synchronize.</p>
<p>SyncExpress is licensed for development and test environments. It is not intended for production. I’m working on some production-ready options for you. For now, just use it to experiment with Correspondence.</p>
<p><strong>Examples</strong> </p>
<p>If you download the source from Codeplex, you will find a Reversi game. Edit the app.config to point the client at your installation of SyncExpress, and you can play a game with a friend.</p>
<p>I am also writing lessons on the Codeplex site taking you step-by-step through building your own Correspondence application. Eventually, I will record screen cast videos of that content.</p>
<p>Please download the bits and follow along with the lessons. I think you’ll find that creating occasionally connected clients has gotten much easier.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=545</wfw:commentRss>
		</item>
		<item>
		<title>Navigate SSRS reports from a web application</title>
		<link>http://adventuresinsoftware.com/blog/?p=542</link>
		<comments>http://adventuresinsoftware.com/blog/?p=542#comments</comments>
		<pubDate>Fri, 30 Jul 2010 17:22:18 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=542</guid>
		<description><![CDATA[I’m on a continuing quest to deliver SSRS reports through a public-facing web application. My user can authenticate, and I can forward their credentials to Report Server. Now I need a branded menu of reports.
Generate a proxy     We’re going to get the list of reports from the Report Server SOAP API. [...]]]></description>
			<content:encoded><![CDATA[<p>I’m on a <a href="http://adventuresinsoftware.com/blog/?p=531">continuing quest to deliver SSRS reports through a public-facing web application</a>. My user can <a href="http://adventuresinsoftware.com/blog/?p=532">authenticate</a>, and I can <a href="http://adventuresinsoftware.com/blog/?p=539">forward their credentials to Report Server</a>. Now I need a branded menu of reports.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image11.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="right" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb11.png" width="244" height="232" /></a><strong>Generate a proxy</strong>     <br />We’re going to get the list of reports from the <a href="http://msdn.microsoft.com/en-us/library/ms154052.aspx">Report Server SOAP API</a>. So first, generate a proxy to call this API. The API is an old-fashioned asmx web service, so you can’t use WCF. Instead, we have to generate a web reference.</p>
<p>Create a new class library called “SQLServerReportingServices”. Right-click and select “Add Service Reference…”. Hit the “Advanced..” button, and then hit the “Add Web Reference” button.</p>
<p>Enter the URL of your report service, followed by “ReportService2010.asmx?wsdl”. You can get this URL by opening Reporting Services Configuration Manager and clicking Web Service URL. I entered “http://dit3074lt2:8080/ReportServer_SQL2008R2/ReportService2010.asmx?wsdl”. Click “Go”.</p>
<p>Enter a meaningful web reference name, like “ReportServer”. This is appended to the class library name to give the namespace of the proxy. So the proxy class is “SQLServerReportingServices.ReportServer.ReportingService2010”. Redundant, I know.</p>
<p><strong>Experiment with the proxy</strong>     <br />Now create a new unit test project. Not because calling an external system like SSRS is a good unit test, but because it’s more convenient than experimenting in a web project. Add a reference to the SQLServerReportingServices class library that you just created. Also, copy the app.config file from SQLServerReportingServices . Finally, add a reference to “System.Web.Services”. Now we can experiment.</p>
<p>Let’s begin by calling the <a href="http://msdn.microsoft.com/en-us/library/reportservice2010.reportingservice2010.listchildren.aspx">ListChildren</a> method. This method gives you a list of CatalogItem objects in a report folder. <a href="http://msdn.microsoft.com/en-us/library/reportservice2010.catalogitem_members.aspx">CatalogItem’s properties</a> give you information about each item, including a Path that you can use in another call to ListChildren. You’re actual number of items will vary, but you should get back an array.</p>
<pre class="code">[<span style="color: #2b91af">TestClass</span>]
<span style="color: blue">public class </span><span style="color: #2b91af">ReportNavigationTest
</span>{
    <span style="color: blue">public </span><span style="color: #2b91af">TestContext </span>TestContext { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

    <span style="color: blue">private </span><span style="color: #2b91af">ReportingService2010 </span>_client;

    [<span style="color: #2b91af">TestInitialize</span>]
    <span style="color: blue">public void </span>Initialize()
    {
        _client = <span style="color: blue">new </span><span style="color: #2b91af">ReportingService2010</span>();
        _client.Credentials = <span style="color: #2b91af">CredentialCache</span>.DefaultCredentials;
    }

    [<span style="color: #2b91af">TestCleanup</span>]
    <span style="color: blue">public void </span>Cleanup()
    {
        _client.Dispose();
    }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>GetTopLevelItems()
    {
        <span style="color: #2b91af">CatalogItem</span>[] children = _client.ListChildren(<span style="color: #a31515">&quot;/&quot;</span>, <span style="color: blue">false</span>);

        <span style="color: #2b91af">Assert</span>.AreEqual(6, children.Length);
    }
}</pre>
<p>If you get the exception “The request failed with HTTP status 401: Unauthorized”, be sure to initialize Credentials. Since you are running the unit test under your own account, the default credentials will be your own. Within the web application, we’ll need to forward the credentials of the logged-in user just like we did in the last post.</p>
<p>After experimenting in the unit test for a bit, we can move to the actual web application.</p>
<p><strong>Walk the folder structure</strong> </p>
<p>In a modern web application, user’s don’t want to click on a folder and wait for a postback to show its contents. If the folder structure is not too deep or too populated, we can display the entire contents on one page. If it is a bit much for one page, then users expect drop-down menus. In either scenario, we need to get the entire folder structure from a single call.</p>
<p>Fortunately, the reporting service lets us get all of the items in one call. Unfortunately, it returns these as a flat array. We have to render it as the folder structure that it truly is. To help with that, we’ll transform the array into a set of classes. See the Composite pattern in your handy Gang of Four book.</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">Item
</span>{
    <span style="color: blue">private string </span>_name;

    <span style="color: blue">public </span>Item(<span style="color: blue">string </span>name)
    {
        _name = name;
    }

    <span style="color: blue">public string </span>Name
    {
        <span style="color: blue">get </span>{ <span style="color: blue">return </span>_name; }
    }

    <span style="color: blue">public abstract void </span>Update();
}

<span style="color: blue">public class </span><span style="color: #2b91af">Folder </span>: <span style="color: #2b91af">Item
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Item</span>&gt; _items = <span style="color: blue">new </span><span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Item</span>&gt;();
    <span style="color: blue">private bool </span>_containsAnyReport;

    <span style="color: blue">public </span>Folder(<span style="color: blue">string </span>name)
        : <span style="color: blue">base</span>(name)
    {
    }

    <span style="color: blue">public void </span>AddItem(<span style="color: #2b91af">Item </span>item)
    {
        _items.Add(item);
    }

    <span style="color: blue">public override void </span>Update()
    {
        <span style="color: green">// Recursively update the items.
        </span><span style="color: blue">foreach </span>(<span style="color: #2b91af">Item </span>item <span style="color: blue">in </span>_items)
            item.Update();

        <span style="color: green">// This folder contains a report if any of its items is a report,
        // or if any of its sub folders contain a report.
        </span>_containsAnyReport =
            _items
                .OfType&lt;<span style="color: #2b91af">Report</span>&gt;()
                .Any() ||
            _items
                .OfType&lt;<span style="color: #2b91af">Folder</span>&gt;()
                .Any(folder =&gt; folder.ContainsAnyReport);
    }

    <span style="color: blue">public bool </span>ContainsAnyReport
    {
        <span style="color: blue">get </span>{ <span style="color: blue">return </span>_containsAnyReport; }
    }

    <span style="color: blue">public </span><span style="color: #2b91af">IEnumerable</span>&lt;<span style="color: #2b91af">Item</span>&gt; Items
    {
        <span style="color: blue">get </span>{ <span style="color: blue">return </span>_items; }
    }
}

<span style="color: blue">public class </span><span style="color: #2b91af">Report </span>: <span style="color: #2b91af">Item
</span>{
    <span style="color: blue">private string </span>_path;

    <span style="color: blue">public </span>Report(<span style="color: blue">string </span>name, <span style="color: blue">string </span>path)
        : <span style="color: blue">base</span>(name)
    {
        _path = path;
    }

    <span style="color: blue">public override void </span>Update()
    {
    }
}</pre>
<p>The Update method walks the structure and updates the ContainsAnyReport property. We can later use this property while rendering the HTML. If the folder does not contain any report, we don’t need to render it. This will hide any folders that the admin created just for data sources or some other resource.</p>
<p>Next we need to turn the flat array into a hierarchy. For this, we use a stack.</p>
<pre class="code"><span style="color: #2b91af">CatalogItem</span>[] children = _client.ListChildren(<span style="color: #a31515">&quot;/&quot;</span>, <span style="color: blue">true</span>);

<span style="color: green">// Keep the current folders on a stack.
</span><span style="color: #2b91af">Folder </span>root = <span style="color: blue">new </span><span style="color: #2b91af">Folder</span>(<span style="color: #a31515">&quot;&quot;</span>);
<span style="color: #2b91af">Stack</span>&lt;<span style="color: #2b91af">Folder</span>&gt; folderStack = <span style="color: blue">new </span><span style="color: #2b91af">Stack</span>&lt;<span style="color: #2b91af">Folder</span>&gt;();
folderStack.Push(root);

<span style="color: green">// Convert the flat array into a folder structure.
</span><span style="color: blue">string </span>currentPath = <span style="color: #a31515">&quot;/&quot;</span>;
<span style="color: #2b91af">Array</span>.Sort(children, (a, b) =&gt; a.Path.CompareTo(b.Path));
<span style="color: blue">foreach </span>(<span style="color: #2b91af">CatalogItem </span>item <span style="color: blue">in </span>children)
{
    <span style="color: green">// Get the path up to and including the final slash.
    </span><span style="color: blue">string </span>parentPath = item.Path.Substring(0, item.Path.LastIndexOf(<span style="color: #a31515">&quot;/&quot;</span>) + 1);
    <span style="color: blue">while </span>(parentPath != currentPath)
    {
        <span style="color: green">// Unwind the stack to get back to the parent folder.
        </span>folderStack.Pop();
        currentPath = currentPath.Substring(0, currentPath.LastIndexOf(<span style="color: #a31515">&quot;/&quot;</span>, currentPath.Length - 2) + 1);
    }

    <span style="color: blue">if </span>(item.TypeName == <span style="color: #a31515">&quot;Folder&quot;</span>)
    {
        <span style="color: green">// Push the new folder to the stack.
        </span><span style="color: #2b91af">Folder </span>folder = <span style="color: blue">new </span><span style="color: #2b91af">Folder</span>(item.Name);
        folderStack.Peek().AddItem(folder);
        folderStack.Push(folder);
        currentPath = item.Path + <span style="color: #a31515">&quot;/&quot;</span>;
    }
    <span style="color: blue">else if </span>(item.TypeName == <span style="color: #a31515">&quot;Report&quot;</span>)
    {
        <span style="color: green">// Add the report to the current folder.
        </span>folderStack.Peek().AddItem(<span style="color: blue">new </span><span style="color: #2b91af">Report</span>(item.Name, item.Path));
    }
}

<span style="color: green">// Figure out which folders contain reports.
</span>root.Update();</pre>
<p>We have to sort the array by the path to ensure that everything in a folder is clumped together. Then we add folders and reports to the current folder. If the path deviates, we pop the stack until we get back on track.</p>
<p>Now you can recursively walk the folder structure to output &lt;div&gt; tags or &lt;ul&gt; lists. That’s an exercise left to the reader, since it will depend upon how you want to render your menu.</p>
<p><strong>Next steps</strong> </p>
<p>As it turns out, we have some applications that don’t authenticate against Active Directory. We would like to use SSRS for those applications as well. For that, we will have to set up a shadow user, which has access to SSRS. Our next step is to implement authentication and authorization for a logged-in user, even though the application accesses SSRS via the shadow user.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=542</wfw:commentRss>
		</item>
		<item>
		<title>Forward network credentials to Report Server</title>
		<link>http://adventuresinsoftware.com/blog/?p=539</link>
		<comments>http://adventuresinsoftware.com/blog/?p=539#comments</comments>
		<pubDate>Tue, 27 Jul 2010 20:52:58 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=539</guid>
		<description><![CDATA[I am on a quest to deliver SSRS reports within a web application. So far we have authenticated against Active Directory using Forms Auth. Now we need to embed a report in our app. Then, we’ll need to forward the logged-on user’s AD credentials to the report server so he can access the report.
  [...]]]></description>
			<content:encoded><![CDATA[<p>I am on a quest to <a href="http://adventuresinsoftware.com/blog/?p=531">deliver SSRS reports within a web application</a>. So far we have <a href="http://adventuresinsoftware.com/blog/?p=532">authenticated against Active Directory using Forms Auth</a>. Now we need to embed a report in our app. Then, we’ll need to forward the logged-on user’s AD credentials to the report server so he can access the report.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image8.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb8.png" width="244" height="117" /></a> <a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image9.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb9.png" width="244" height="86" /></a> <a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image10.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb10.png" width="244" height="120" /></a> </p>
<p>For now, I’m just going to add a report to Default.aspx. Later on, we’ll provide a menu to navigate the user’s reports. First, drag a “MicrosoftreportViewer” control from the Toolbox onto the designer. Then, click the task button, open “Choose Report”, and select “&lt;Server Report&gt;”. Fill in your Report Server URL, which you can get by launching “Reporting Services Configuration Manager” and selecting the Web Service URL. Enter the path to the report that you created earlier. Your page source should look like this.</p>
<pre class="code"><span style="background: #ffee62">&lt;%</span><span style="color: blue">@ </span><span style="color: #a31515">Page </span><span style="color: red">Language</span><span style="color: blue">=&quot;C#&quot; </span><span style="color: red">AutoEventWireup</span><span style="color: blue">=&quot;true&quot; </span><span style="color: red">CodeBehind</span><span style="color: blue">=&quot;Default.aspx.cs&quot; </span><span style="color: red">Inherits</span><span style="color: blue">=&quot;WebApplication1._Default&quot; </span><span style="background: #ffee62">%&gt;

&lt;%</span><span style="color: blue">@ </span><span style="color: #a31515">Register </span><span style="color: red">assembly</span><span style="color: blue">=&quot;Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&quot; </span><span style="color: red">namespace</span><span style="color: blue">=&quot;Microsoft.Reporting.WebForms&quot; </span><span style="color: red">tagprefix</span><span style="color: blue">=&quot;rsweb&quot; </span><span style="background: #ffee62">%&gt;

</span><span style="color: blue">&lt;!</span><span style="color: #a31515">DOCTYPE </span><span style="color: red">html PUBLIC </span><span style="color: blue">&quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;</span><span style="color: #a31515">html </span><span style="color: red">xmlns</span><span style="color: blue">=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
&lt;</span><span style="color: #a31515">head </span><span style="color: red">runat</span><span style="color: blue">=&quot;server&quot;&gt;
    &lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">head</span><span style="color: blue">&gt;
&lt;</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">form </span><span style="color: red">id</span><span style="color: blue">=&quot;form1&quot; </span><span style="color: red">runat</span><span style="color: blue">=&quot;server&quot;&gt;
    &lt;</span><span style="color: #a31515">div</span><span style="color: blue">&gt;

        &lt;</span><span style="color: #a31515">rsweb</span><span style="color: blue">:</span><span style="color: #a31515">ReportViewer </span><span style="color: red">ID</span><span style="color: blue">=&quot;ReportViewer1&quot; </span><span style="color: red">runat</span><span style="color: blue">=&quot;server&quot; </span><span style="color: red">Font-Names</span><span style="color: blue">=&quot;Verdana&quot;
            </span><span style="color: red">Font-Size</span><span style="color: blue">=&quot;8pt&quot; </span><span style="color: red">Height</span><span style="color: blue">=&quot;400px&quot; </span><span style="color: red">Width</span><span style="color: blue">=&quot;100%&quot; </span><span style="color: red">ProcessingMode</span><span style="color: blue">=&quot;Remote&quot;&gt;
            &lt;</span><span style="color: #a31515">ServerReport </span><span style="color: red">ReportPath</span><span style="color: blue">=&quot;/Admin Report&quot;
                </span><span style="color: red">ReportServerUrl</span><span style="color: blue">=&quot;http://dit3074lt2:8080/ReportServer_SQL2008R2&quot; /&gt;
        &lt;/</span><span style="color: #a31515">rsweb</span><span style="color: blue">:</span><span style="color: #a31515">ReportViewer</span><span style="color: blue">&gt;

    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">form</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">html</span><span style="color: blue">&gt;
</span></pre>
<p>If you run the application right now, it looks like it all works! That’s because you are running a local web server under your own account. Your credentials are passed to the report server. We want to pass the logged-in user’s credentials to Report Server, so he can only access the reports to which he has been given permission.</p>
<p><strong>Provide credentials to report Server</strong></p>
<p>To pass credentials to Report Server, we set the ReportViewer.ServerReport.ReportServerCredentials property to an IReportServerCredentials. There are many ways to implement this interface. The simplest way is to provide a NetworkCredentials object.</p>
</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">NetworkReportServerCredentials </span>: <span style="color: #2b91af">IReportServerCredentials
</span>{
    <span style="color: blue">private string </span>_userName;
    <span style="color: blue">private string </span>_password;
    <span style="color: blue">private string </span>_domain;

    <span style="color: blue">public </span>NetworkReportServerCredentials(<span style="color: blue">string </span>userName, <span style="color: blue">string </span>password, <span style="color: blue">string </span>domain)
    {
        _userName = userName;
        _password = password;
        _domain = domain;
    }

    <span style="color: blue">public bool </span>GetFormsCredentials(<span style="color: blue">out </span><span style="color: #2b91af">Cookie </span>authCookie, <span style="color: blue">out string </span>userName, <span style="color: blue">out string </span>password, <span style="color: blue">out string </span>authority)
    {
        authCookie = <span style="color: blue">null</span>;
        userName = <span style="color: blue">null</span>;
        password = <span style="color: blue">null</span>;
        authority = <span style="color: blue">null</span>;
        <span style="color: blue">return false</span>;
    }

    <span style="color: blue">public </span><span style="color: #2b91af">WindowsIdentity </span>ImpersonationUser
    {
        <span style="color: blue">get </span>{ <span style="color: blue">return null</span>; }
    }

    <span style="color: blue">public </span><span style="color: #2b91af">ICredentials </span>NetworkCredentials
    {
        <span style="color: blue">get </span>{ <span style="color: blue">return new </span><span style="color: #2b91af">NetworkCredential</span>(_userName, _password, _domain); }
    }
}</pre>
<p>This implementation only provides a meaningful implementation to the NetworkCredentials property. It just returns the credentials that it was given. We have to get the user’s credentials into this object when we access the report. We captured the user’s credentials when he logged in, but we didn’t save them anywhere. We need to save them during login so we can access them while viewing the report.</p>
<p>During login, we have the opportunity to populate a FormsAuthenticationTicket. This is the object that gets stored in the user’s Forms Authorization cookie. This class holds the user’s name, but not their password. However, it does have a UserData property that we can use however we want.</p>
<p><strong>Cryptography required</strong></p>
<p>Now, we could just put the plaintext password into UserData. But we aren’t going to do that. This object is cached as a cookie in the user’s browser. Storing their plaintext password in a cookie would reveal it to anyone who had access to their machine. Even without direct access to the machine, a cross-site scripting attack could compel the browser to give up its cookie. We will not expose the user to that kind of vulnerability.</p>
<p>Instead, we are going to encrypt the password using a secret key that we store on the server. An attacker would need access to this key if they were going to pull the user’s password from their cookie. First, we create some useful crypto helpers:</p>
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">Crypto
</span>{
    <span style="color: blue">public static byte</span>[] EncryptMessage(
        <span style="color: blue">string </span>messageIn,
        <span style="color: #2b91af">SymmetricAlgorithm </span>symmetricAlgorithm,
        <span style="color: blue">byte</span>[] key,
        <span style="color: blue">byte</span>[] initializationVector)
    {
        <span style="color: #2b91af">MemoryStream </span>memoryStream = <span style="color: blue">new </span><span style="color: #2b91af">MemoryStream</span>();
        <span style="color: blue">using </span>(<span style="color: #2b91af">StreamWriter </span>cryptoWriter = <span style="color: blue">new </span><span style="color: #2b91af">StreamWriter</span>(
            <span style="color: blue">new </span><span style="color: #2b91af">CryptoStream</span>(
                memoryStream,
                symmetricAlgorithm.CreateEncryptor(key, initializationVector),
                <span style="color: #2b91af">CryptoStreamMode</span>.Write)))
        {
            cryptoWriter.Write(messageIn);
        }

        <span style="color: blue">return </span>memoryStream.ToArray();
    }

    <span style="color: blue">public static string </span>DecryptMessage(
        <span style="color: blue">byte</span>[] encryptedMessage,
        <span style="color: #2b91af">SymmetricAlgorithm </span>symmetricAlgorithm,
        <span style="color: blue">byte</span>[] key,
        <span style="color: blue">byte</span>[] initializationVector)
    {
        <span style="color: #2b91af">MemoryStream </span>memoryStream = <span style="color: blue">new </span><span style="color: #2b91af">MemoryStream</span>(encryptedMessage);
        <span style="color: blue">using </span>(<span style="color: #2b91af">StreamReader </span>cryptoReader = <span style="color: blue">new </span><span style="color: #2b91af">StreamReader</span>(
            <span style="color: blue">new </span><span style="color: #2b91af">CryptoStream</span>(
                memoryStream,
                symmetricAlgorithm.CreateDecryptor(key, initializationVector),
                <span style="color: #2b91af">CryptoStreamMode</span>.Read)))
        {
            <span style="color: blue">return </span>cryptoReader.ReadToEnd();
        }
    }

    <span style="color: blue">public static byte</span>[] ComputeStringHash(<span style="color: blue">string </span>message, <span style="color: #2b91af">HashAlgorithm </span>hashAlgorith)
    {
        <span style="color: blue">byte</span>[] messageBytes = <span style="color: #2b91af">ASCIIEncoding</span>.ASCII.GetBytes(message);
        <span style="color: blue">return </span>hashAlgorith.ComputeHash(messageBytes);
    }
}</pre>
<p>The first two methods encrypt and decrypt a string using a symmetrical algorithm. The encrypted message is binary, so it is represented as a byte array. I found it exceedingly difficult to get these steps right, even though the code turned out to be almost trivial. The third method hardly deserves to be included with the others, but it comes in handy.</p>
<p>Let’s see how these methods are used.</p>
<pre class="code">[<span style="color: #2b91af">TestClass</span>]
<span style="color: blue">public class </span><span style="color: #2b91af">CryptoStreamTest
</span>{
    <span style="color: blue">private const string </span>PreGeneratedKey = <span style="color: #a31515">@&quot;s03UsP/dHD0=&quot;</span>;
    <span style="color: blue">private </span><span style="color: #2b91af">SymmetricAlgorithm </span>_symmetricAlgorithm = <span style="color: blue">new </span><span style="color: #2b91af">DESCryptoServiceProvider</span>();
    <span style="color: blue">private </span><span style="color: #2b91af">HashAlgorithm </span>_hashAlgorith = <span style="color: blue">new </span><span style="color: #2b91af">MD5CryptoServiceProvider</span>();
    <span style="color: blue">private </span><span style="color: #2b91af">RandomNumberGenerator </span>_randomNumberGenerator = <span style="color: blue">new </span><span style="color: #2b91af">RNGCryptoServiceProvider</span>();
    <span style="color: blue">private static byte</span>[] _key = <span style="color: #2b91af">Convert</span>.FromBase64String(PreGeneratedKey);

    <span style="color: blue">public </span><span style="color: #2b91af">TestContext </span>TestContext { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>GenerateKey()
    {
        <span style="color: blue">byte</span>[] key = <span style="color: blue">new byte</span>[_symmetricAlgorithm.KeySize / 8];
        _randomNumberGenerator.GetBytes(key);
        <span style="color: blue">string </span>encodedKey = <span style="color: #2b91af">Convert</span>.ToBase64String(key);
        <span style="color: #2b91af">Assert</span>.AreNotEqual(PreGeneratedKey, encodedKey);
        <span style="color: #2b91af">Console</span>.WriteLine(encodedKey);
    }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>EncryptAndDecryptStream()
    {
        <span style="color: blue">byte</span>[] initializationVector = <span style="color: blue">new byte</span>[_symmetricAlgorithm.KeySize / 8];
        _randomNumberGenerator.GetBytes(initializationVector);
        <span style="color: blue">byte</span>[] encryptedMessage = <span style="color: #2b91af">Crypto</span>.EncryptMessage(<span style="color: #a31515">&quot;plaintext&quot;</span>, _symmetricAlgorithm, _key, initializationVector);
        <span style="color: blue">string </span>messageOut = <span style="color: #2b91af">Crypto</span>.DecryptMessage(encryptedMessage, _symmetricAlgorithm, _key, initializationVector);

        <span style="color: #2b91af">Assert</span>.AreEqual(<span style="color: #a31515">&quot;plaintext&quot;</span>, messageOut);
    }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>InitializationVectorIsImportant()
    {
        <span style="color: blue">byte</span>[] initializationVector1 = <span style="color: blue">new byte</span>[_symmetricAlgorithm.KeySize / 8];
        _randomNumberGenerator.GetBytes(initializationVector1);
        <span style="color: blue">byte</span>[] initializationVector2 = <span style="color: blue">new byte</span>[_symmetricAlgorithm.KeySize / 8];
        _randomNumberGenerator.GetBytes(initializationVector2);
        <span style="color: blue">byte</span>[] encryptedMessage = <span style="color: #2b91af">Crypto</span>.EncryptMessage(<span style="color: #a31515">&quot;plaintext&quot;</span>, _symmetricAlgorithm, _key, initializationVector1);
        <span style="color: blue">string </span>messageOut = <span style="color: #2b91af">Crypto</span>.DecryptMessage(encryptedMessage, _symmetricAlgorithm, _key, initializationVector2);

        <span style="color: #2b91af">Assert</span>.AreNotEqual(<span style="color: #a31515">&quot;plaintext&quot;</span>, messageOut);
    }

    [<span style="color: #2b91af">TestMethod</span>]
    <span style="color: blue">public void </span>HashMessage()
    {
        <span style="color: blue">byte</span>[] hash = <span style="color: #2b91af">Crypto</span>.ComputeStringHash(<span style="color: #a31515">&quot;This is the string that we intend to sign.&quot;</span>, _hashAlgorith);
        <span style="color: blue">string </span>encodedHash = <span style="color: #2b91af">Convert</span>.ToBase64String(hash);
        <span style="color: #2b91af">Assert</span>.AreEqual(<span style="color: #a31515">@&quot;04fj0UWULE9imGTrHRUw5g==&quot;</span>, encodedHash);
    }
}</pre>
<p>To generate a key, we use the cryptographic random number generator RNGCryptoServiceProvider. This produces a binary array of the key length required by our symmetrical encryption algorithm. Convert the binary array to a base 64 string for easy portability. I generated one ahead of time for use with the remaining tests.</p>
<p>To encrypt and decrypt a string, we must provide not only a key but also an initialization vector. The initialization vector is a starting point for the symmetrical algorithm. Encryption and decryption must both start at the same point. The trick is that we don’t want to use the same initialization vector every time, because that would mean we always produce the same cyphertext for a given plaintext. An attacker could simply create an account with a common password (say, “password”), and then look for other users with the same cyphertext as he has. Bingo! He knows that their password is “password”!</p>
<p>Finally, we test computing the hash of a string. This is usually used to digitally sign a message, but we have another use for it.</p>
<p><strong>Encrypt the user’s password</strong></p>
<p>We want to encrypt the user’s password. For that we’ll need a key; you can generate one with the first unit test above. But we will also need an initialization vector. Remember, we need to use the same initialization vector for encrypting as well as decrypting. And we’ll also need it to be different for each user. The simple solution: use the hash of the username.</p>
<pre class="code"><span style="color: blue">protected void </span>Login1_Authenticate(<span style="color: blue">object </span>sender, <span style="color: #2b91af">AuthenticateEventArgs </span>e)
{
    <span style="color: blue">string </span>username = Login1.UserName;
    <span style="color: blue">string </span>password = Login1.Password;

    <span style="color: green">// MLP: Encrypt the password.
    </span><span style="color: blue">byte</span>[] usernameHash = <span style="color: #2b91af">Crypto</span>.ComputeStringHash(username, _hashAlgorith);
    <span style="color: blue">byte</span>[] encryptedMessage = <span style="color: #2b91af">Crypto</span>.EncryptMessage(password, _symmetricAlgorithm, _key, usernameHash);
    <span style="color: blue">string </span>encryptedPassword = <span style="color: #2b91af">Convert</span>.ToBase64String(encryptedMessage);

    <span style="color: blue">if </span>(<span style="color: #2b91af">Membership</span>.ValidateUser(username, password))
    {
        e.Authenticated = <span style="color: blue">true</span>;

        <span style="color: #2b91af">FormsAuthenticationTicket </span>ticket = <span style="color: blue">new </span><span style="color: #2b91af">FormsAuthenticationTicket</span>(
            1,
            username,
            <span style="color: #2b91af">DateTime</span>.Now,
            <span style="color: #2b91af">DateTime</span>.Now.AddMinutes(30),
            <span style="color: blue">false</span>,
            encryptedPassword,
            <span style="color: #2b91af">FormsAuthentication</span>.FormsCookiePath);

        <span style="color: green">// MLP: This method should be called &quot;Encode&quot;, not &quot;Encrypt&quot;.
        </span><span style="color: blue">string </span>encTicket = <span style="color: #2b91af">FormsAuthentication</span>.Encrypt(ticket);

        <span style="color: green">// Create the cookie.
        </span>Response.Cookies.Add(<span style="color: blue">new </span><span style="color: #2b91af">HttpCookie</span>(<span style="color: #2b91af">FormsAuthentication</span>.FormsCookieName, encTicket));

        <span style="color: green">// Redirect back to original URL.
        </span>Response.Redirect(<span style="color: #2b91af">FormsAuthentication</span>.GetRedirectUrl(username, <span style="color: blue">false</span>));
    }
    <span style="color: blue">else
    </span>{
        e.Authenticated = <span style="color: blue">false</span>;
    }
}</pre>
<p>Hold on a second. If we are calling FormsAuthentication.Encrypt(), why are we bothering to encrypt the password first? Unfortunately, Encrypt() is not secure. It doesn’t take a key. That means that anyone with access to the .NET Framework can simply call Decrypt() to get back the ticket. I would prefer if the method was called Encode().</p>
<p><strong>Decrypt the user’s password</strong></p>
<p>The last step is to access the encrypted password, decrypt it, and pass the credentials to Report Server. We accomplish this with a minimum of code:</p>
<pre class="code"><span style="color: blue">protected void </span>Page_Load(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
    <span style="color: green">// MLP: Get the user's credentials from forms auth.
    </span><span style="color: #2b91af">IIdentity </span>identity = <span style="color: #2b91af">HttpContext</span>.Current.User.Identity;
    <span style="color: #2b91af">FormsIdentity </span>formsIdentity = (<span style="color: #2b91af">FormsIdentity</span>)identity;
    <span style="color: blue">string </span>username = formsIdentity.Name;
    <span style="color: blue">string </span>encryptedPassword = formsIdentity.Ticket.UserData;

    <span style="color: green">// MLP: Decrypt the password.
    </span><span style="color: blue">byte</span>[] usernameHash = <span style="color: #2b91af">Crypto</span>.ComputeStringHash(username, _hashAlgorith);
    <span style="color: blue">byte</span>[] encryptedMessage = <span style="color: #2b91af">Convert</span>.FromBase64String(encryptedPassword);
    <span style="color: blue">string </span>password = <span style="color: #2b91af">Crypto</span>.DecryptMessage(encryptedMessage, _symmetricAlgorithm, _key, usernameHash);

    <span style="color: #2b91af">IReportServerCredentials </span>credentials = <span style="color: blue">new </span><span style="color: #2b91af">NetworkReportServerCredentials</span>(username, password, <span style="color: #a31515">&quot;ABSG&quot;</span>);
    ReportViewer1.ServerReport.ReportServerCredentials = credentials;
}</pre>
<p>And so we have passed the user’s network credentials on to Report Server. They were authenticated against Active Directory, which is the identity provider that SSRS prefers. However, we did all this in forms authentication so that our web application works better with users on the Internet.</p>
<p><strong>Next steps</strong></p>
<p>Next we are going to provide a menu of reports to the user. The business administrator should be able to define new reports without requiring any change to our application.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=539</wfw:commentRss>
		</item>
		<item>
		<title>Forms Authentication and the Active Directory membership provider</title>
		<link>http://adventuresinsoftware.com/blog/?p=532</link>
		<comments>http://adventuresinsoftware.com/blog/?p=532#comments</comments>
		<pubDate>Mon, 26 Jul 2010 20:58:14 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=532</guid>
		<description><![CDATA[We have reports published to SQL Server Reporting Services, and we want users to access those reports from a web application. We could give them direct access to Report Manager, but we choose not to. The Report Manager UI displays concepts in the reporting domain, not concepts in our problem domain (healthcare). We want to [...]]]></description>
			<content:encoded><![CDATA[<p>We have reports published to SQL Server Reporting Services, and we want users to access those reports from a web application. We could give them direct access to Report Manager, but we choose not to. The Report Manager UI displays concepts in the reporting domain, not concepts in our problem domain (healthcare). We want to give the users a simpler, branded experience, while still giving them access to reports created by a business administrator, not a developer.</p>
<p>SSRS uses Active Directory for authentication. While it is theoretically possible to change the authentication provider, this is exceedingly difficult. In prior releases, SSRS ran both the Report Manager and the Web Service in IIS, which lets you to choose to allow anonymous access. As of SQL Server 2008, SSRS hosts these services itself. It does not expose the anonymous access option. So even if you change the authentication provider for the reports, you must first get past the web server security. The net effect is that your users need to be in Active Directory.</p>
<p>Fortunately for us, we use Active Directory for authentication. We just don’t use Windows Authentication for the web application. That makes this design feasible.</p>
<p><strong>Use Forms Authentication</strong>     <br />When you create a new ASP .NET web application, it is initially configured to use Windows Authentication. This allows a user within the domain to use their credentials to access the application without re-authenticating. Since they are logged in to Windows, those credentials get passed through to the app.</p>
<p>In our case, however, our users are not logged in to our domain. They access the application over the Internet. They may not even be running Windows. So we have to use Forms Authentication.</p>
<p>Even though our users aren’t on our domain, we still use Active Directory as an identity store. Fortunately, it’s possible to <a href="http://msdn.microsoft.com/en-us/library/ff650308.aspx">use Forms Authentication with Active Directory</a>.</p>
<p>Create a new ASP.NET Web Application project. This can also be done with MVC, but our existing application was written prior to its release. Add a new Web Form to the project called “Login.aspx”. Add an asp:Login control to the page. You can just drag one from the toolbox.</p>
<p>Double-click the login control to handle the Authenticate event. This event will be called when the user presses the Login button. For now, we’ll use FormsAuthentication.Authenticate. We’ll change that in a little bit.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">form </span><span style="color: red">id</span><span style="color: blue">=&quot;form1&quot; </span><span style="color: red">runat</span><span style="color: blue">=&quot;server&quot;&gt;
    &lt;</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    <strong>&lt;</strong></span><strong><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Login </span><span style="color: red">ID</span><span style="color: blue">=&quot;Login1&quot; </span><span style="color: red">runat</span><span style="color: blue">=&quot;server&quot; </span><span style="color: red">onauthenticate</span></strong><span style="color: blue"><strong>=&quot;Login1_Authenticate&quot;&gt;
</strong>    <strong>&lt;/</strong></span><strong><span style="color: #a31515">asp</span><span style="color: blue">:</span><span style="color: #a31515">Login</span></strong><span style="color: blue"><strong>&gt;</strong>
    &lt;/</span><span style="color: #a31515">div</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">form</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">body</span><span style="color: blue">&gt;
</span></pre>
<pre class="code"><span style="color: blue">protected void </span>Login1_Authenticate(<span style="color: blue">object </span>sender, <span style="color: #2b91af">AuthenticateEventArgs </span>e)
{
    e.Authenticated = <span style="color: #2b91af">FormsAuthentication</span>.Authenticate(Login1.UserName, Login1.Password);
}</pre>
<p>Edit the web.config file to use forms authentication. Create a user credential to make sure everything is working so far.</p>
<pre class="code">    <span style="color: blue">&lt;!-- </span><span style="color: green">MLP: Changed this from &quot;Windows&quot; to &quot;Forms&quot;. </span><span style="color: blue">--&gt;
    &lt;</span><span style="color: #a31515">authentication </span><span style="color: red">mode</span><span style="color: blue">=</span>&quot;<span style="color: blue"><strong>Forms</strong></span>&quot;<span style="color: blue">&gt;
      &lt;!-- </span><span style="color: green">MLP: Added Login.aspx and .ASPXFORMSAUTH settings. </span><span style="color: blue">--&gt;
      &lt;</span><span style="color: #a31515">forms </span><span style="color: red">loginUrl</span><span style="color: blue">=</span>&quot;<span style="color: blue">Login.aspx</span>&quot; <span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">.ASPXFORMSAUTH</span>&quot;<span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">credentials </span><span style="color: red">passwordFormat</span><span style="color: blue">=</span>&quot;<span style="color: blue">Clear</span>&quot;<span style="color: blue">&gt;
          &lt;</span><span style="color: #a31515">user </span><span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">test</span>&quot; <span style="color: red">password</span><span style="color: blue">=</span>&quot;<span style="color: blue">pass</span>&quot;<span style="color: blue">/&gt;
        &lt;/</span><span style="color: #a31515">credentials</span><span style="color: blue">&gt;
      &lt;/</span><span style="color: #a31515">forms</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">authentication</span><span style="color: blue">&gt;
    &lt;!-- </span><span style="color: green">MLP: Deny unauthenticated users access to other pages. </span><span style="color: blue">--&gt;
    &lt;</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">deny </span><span style="color: red">users</span><span style="color: blue">=</span>&quot;<span style="color: blue">?</span>&quot; <span style="color: blue">/&gt;
    &lt;/</span><span style="color: #a31515">authorization</span><span style="color: blue">&gt;
</span></pre>
<p>Hit F5 and test your site. You should be redirected from your default page to the login page. If you enter the wrong credentials, you’ll get an error. If you enter user “test” and password “pass”, you’ll get to your default page.</p>
<p><strong>Set up the Active Directory membership provider</strong> </p>
<p>Now that we have forms authentication working, let’s switch to using membership. “Membership” is a provider-based system for managing identity and role-based security. By default, membership uses a SQL database to store credentials. You can switch to the Active Directory provider instead.</p>
<p>Active Directory is very similar to a relational database. You access it via a connection string. Access is restricted to specific users. The main difference is that AD is a hierarchical store, while a database is a relational store. AD is typically used to store information about users, groups, and machines within a domain. That’s what the Active Directory membership provider expects.</p>
<p>If you didn’t set up AD yourself, you will need to talk to the person who did. Get a connection string, username, and password that gives you read-only access to the server. If you would like to try this yourself before involving your network operator, you can set up a <a href="http://adventuresinsoftware.com/blog/?p=151">virtual network in Microsoft Virtual PC</a>.</p>
<p>To configure the Active Directory membership provider, add this to web.config after the &lt;authorization&gt; tag you added earlier. Pay close attention to the enablePasswordReset and attributeMapUsername settings. These are not mentioned in the Patterns and Practices guidance, but I found them to be necessary while working in my environment. The AD account that I have does not have permission to reset passwords. And my company’s directory does not set the userPrincipleName, which is the default.</p>
<pre class="code">    <span style="color: blue">&lt;!-- </span><span style="color: green">MLP: Use the Active Directory membership provider. </span><span style="color: blue">--&gt;
    &lt;</span><span style="color: #a31515">membership </span><span style="color: red">defaultProvider</span><span style="color: blue">=</span>&quot;<span style="color: blue">ADMembershipProvider</span>&quot;<span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">providers</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">add
           </span><span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">ADMembershipProvider</span>&quot;
           <span style="color: red">type</span><span style="color: blue">=</span>&quot;<span style="color: blue">System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0,
             Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</span>&quot;
           <span style="color: red">connectionStringName</span><span style="color: blue">=</span>&quot;<span style="color: blue">ADConnectionString</span>&quot;
           <span style="color: red">connectionUsername</span><span style="color: blue">=</span>&quot;<span style="color: blue">MyDomain\MyADUserName</span>&quot;
           <span style="color: red">connectionPassword</span><span style="color: blue">=</span>&quot;<span style="color: blue">MyADPassword</span>&quot;
           <strong><span style="color: red">enablePasswordReset</span><span style="color: blue">=</span>&quot;<span style="color: blue">false</span>&quot;</strong>
           <strong><span style="color: red">attributeMapUsername</span><span style="color: blue">=</span>&quot;<span style="color: blue">sAMAccountName</span>&quot;</strong><span style="color: blue">/&gt;
      &lt;/</span><span style="color: #a31515">providers</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">membership</span><span style="color: blue">&gt;
</span></pre>
<p>Replace MyDomain and MyADUserName with the correct values. Remove the &lt;credentials&gt; element from &lt;forms&gt;. You won’t need the hard-coded credentials any more. Add the connection string to the top of the file: </p>
<pre class="code">  <span style="color: blue">&lt;</span><span style="color: #a31515">connectionStrings</span><span style="color: blue">&gt;
</span><span style="color: blue">    &lt;!-- </span><span style="color: green">MLP: Added connection string for Active Directory authentication. –</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">add </span><span style="color: red">name</span><span style="color: blue">=</span>&quot;<span style="color: blue">ADConnectionString</span>&quot; <span style="color: red">connectionString</span><span style="color: blue">=</span>&quot;<span style="color: blue">LDAP://MyADMachine/DC=MyDomain,DC=MyTLD</span>&quot; <span style="color: blue">/&gt;
  &lt;/</span><span style="color: #a31515">connectionStrings</span><span style="color: blue">&gt;
</span></pre>
<p>Again, replace MyADMachine, MyDomain, and MyTLD with the values you get from your network admin. You might already have a &lt;connectionStrings&gt; section at the top. Just make sure you have a closing tag and insert the &lt;add …&gt; line. </p>
<p>Finally, we need to change the code to use Membership instead of FormsAuthentication. Change the code that you added before to Login1_Authenticate.</p>
<pre class="code"><span style="color: blue">protected void </span>Login1_Authenticate(<span style="color: blue">object </span>sender, <span style="color: #2b91af">AuthenticateEventArgs </span>e)
{
    e.Authenticated = <span style="color: #2b91af">Membership</span>.ValidateUser(Login1.UserName, Login1.Password);
}</pre>
<p>Now run the program again and try to log in with your network credentials. In fact, you can delete your onauthenticate handler altogether. The line of code above is exactly what the login control does by default.</p>
<p><strong>Next steps</strong> </p>
<p>Now that we are logged in using an Active Directory account, we’ll access an SSMS report using those credentials.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=532</wfw:commentRss>
		</item>
		<item>
		<title>Application reports in SSRS</title>
		<link>http://adventuresinsoftware.com/blog/?p=531</link>
		<comments>http://adventuresinsoftware.com/blog/?p=531#comments</comments>
		<pubDate>Fri, 23 Jul 2010 14:51:45 +0000</pubDate>
		<dc:creator>Michael L Perry</dc:creator>
		
		<category><![CDATA[Reports]]></category>

		<guid isPermaLink="false">http://adventuresinsoftware.com/blog/?p=531</guid>
		<description><![CDATA[I’ve been researching SQL Server Reporting Services. Our goal is to let users of our application view reports created by a business administrator. The application uses Active Directory via forms authentication. It has its own custom authorization.
There are two ways to create a report in SSRS. One way is to use Visual Studio. The second [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve been researching SQL Server Reporting Services. Our goal is to let users of our application view reports created by a business administrator. The application uses Active Directory via forms authentication. It has its own custom authorization.</p>
<p>There are two ways to create a report in SSRS. One way is to use Visual Studio. The second is to use the Report Builder on line in the Report Manger site. I’ll use Visual Studio to get started. I’m using SQL Server 2008 R2 and Visual Studio 2008.</p>
<p><strong>Create a Report Server Project</strong>    <br /><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image1.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 5px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="left" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb1.png" width="244" height="161" /></a>First create a Report Server project. I’m using the Report Server Project Wizard in the Business Intelligence Projects section. If you don’t see Business Intelligence Projects, please be sure to <a href="http://msdn.microsoft.com/en-us/library/ms143736.aspx">install SQL Server Reporting Services</a> on your development box.</p>
</p>
<p>Create a new data source by setting up a connection string. Since we are creating application reports, we connect to the development application database. You can hit the “Edit” button to help you out, or just copy the connection string from the web.config file of your application.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image2.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 0px 0px 5px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="right" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb2.png" width="244" height="225" /></a> My application uses a specific SQL account to access the database. This is not the end-user’s account. I entered these credentials while creating the connection string. The username and password are not visible in the generated connection string, but I can see that they’ve been stored if I hit the “Credentials” button.</p>
<p> Next the wizard prompts you to create a query. Define a query that selects and groups the data the way that it will be displayed on the report. The report can do little more than place the data in the right boxes. You’ll need the query to do the heavy lifting.<a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image3.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 5px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="left" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb3.png" width="244" height="128" /></a></p>
<p>Then, you create your report. I selected a “Matrix” report, which allows me put data on both rows and columns. You might also know this as a “crosstab” report. My query has four columns, which is the ideal number for a matrix report. I added the highest-level concept to the “Page” box, the grouping concepts to “Rows” and “Columns”, and the lowest-level value to “Details”. Avoid putting more than one column in these boxes, because that will turn a simple matrix report into a complex tree.</p>
<p>Finally, give the URL of your reporting server. You can find this URL by running “Microsoft SQL Server 2008 R2”, “Configuration Tools”, “Reporting Services Configuration Manager”. Click on “Web Service URL” and select the hyperlink.</p>
</p>
<p><strong>Deploy the report</strong>    <br />You now have a project containing a single .rdl file. This is a report definition that SSRS can run. You can run the report now by pressing F5. For others to run the report, it will need to reside on the report server.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image4.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 5px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="left" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb4.png" width="244" height="158" /></a> By default, the project is not deployable. Select “Build”, “Configuration Manager” to change this. Check the box under “Deploy” for your report project.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image5.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 0px 0px 5px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="right" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb5.png" width="244" height="160" /></a> To deploy the project, select “Build”, “Deploy Solution”. The .rdl file will be copied to the reporting server. You can now see the report on line. Go back to the Reporting Services Configuration Manager, but this time choose the “Report Manager URL” section. Click the hyperlink to open the report manager in the browser.</p>
<p>The report was deployed to a folder that you named in the wizard. Mine is in IONReports. Click on the folder, and then click on the report to view it.</p>
<p>&#160;</p>
</p>
<p>You probably want other people to be able to access the report. Right now, it is probably deployed to SSRS running on localhost. To deploy it to a remote server, first ensure that SSRS is installed on the target machine. Then you can run the Reporting Services Configuration Manager on that server to find the Web Service URL.<a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image6.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 5px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="left" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb6.png" width="244" height="164" /></a></p>
<p>Right click on the report server project in Visual Studio and choose “Properties”. This brings up a property page where you can edit the settings that you configured using the wizard. Enter the remote server’s Web Service URL in the TargetServerURL. You can now deploy the report to a server where others can run it.</p>
<p><a href="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image7.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 0px 0px 5px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="right" src="http://adventuresinsoftware.com/blog/wp-content/uploads/2010/07/image-thumb7.png" width="244" height="160" /></a> Once the report is deployed, others can edit it on line using the Report Manager. Instead of clicking to run the report, pull down the menu. Choose “Edit in Report Builder”. The report builder is not quite as slick as the Visual Studio wizard, but it gets the job done. The connection, query, and report layout that you created in Visual Studio are all editable from within the report builder. You just might have to use text instead of a visual interface.</p>
<p>A business admin can edit and create reports using this interface. It may be easier for everyone if a developer or DBA designs the queries to start with. A developer would most likely be using a Visual Studio report server project, whereas the DBA would probably create a view. But once they have help getting started, the business admin can take over.</p>
<p><strong>Next steps</strong>    <br />Remember, the goal is to access reports from within an application. The admin uses the Report Manager, but the end user needs a simpler, branded interface. We’ll tackle that in the next article.</p>
]]></content:encoded>
			<wfw:commentRss>http://adventuresinsoftware.com/blog/?feed=rss2&amp;p=531</wfw:commentRss>
		</item>
	</channel>
</rss>
