7

When my Razor view calls @Html.OpenIdSelector(... I get an InvalidOperationException:

The current IHttpHandler is not one of types: System.Web.UI.Page, DotNetOpenAuth.IEmbeddedResourceRetrieval. An embedded resource URL provider must be set in your .config file.

What exactly should I set in the config file?

Andrew Arnott
  • 80,040
  • 26
  • 132
  • 171
CD..
  • 72,281
  • 25
  • 154
  • 163

2 Answers2

8

Just NuGet the DotNetOpenAuth package. It will setup everything you need in your config file:

alt text

  1. Right click on the References of your web project in the solution explorer
  2. Add Library Package Reference...
  3. Click on the Online tab.
  4. In the search box type dotnetopenauth
  5. Click Install

Everything will be automatically setup and the correct assemblies will be downloaded from the internet and added as reference.

Here's how the web.config file looks like after performing this:

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>
  <configSections>
    <section name="uri" type="System.Configuration.UriSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <section name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection" requirePermission="false" allowLocation="true" />
  </configSections>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
    <membership>
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <profile>
      <providers>
        <clear />
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear />
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
    <legacyHMACWarning enabled="0" />
  </runtime>
  <uri>
    <!-- The uri section is necessary to turn on .NET 3.5 support for IDN (international domain names),
         which is necessary for OpenID urls with unicode characters in the domain/host name. 
         It is also required to put the Uri class into RFC 3986 escaping mode, which OpenID and OAuth require. -->
    <idn enabled="All" />
    <iriParsing enabled="true" />
  </uri>
  <system.net>
    <defaultProxy enabled="true" />
    <settings>
      <!-- This setting causes .NET to check certificate revocation lists (CRL) 
                 before trusting HTTPS certificates.  But this setting tends to not 
                 be allowed in shared hosting environments. -->
      <!--<servicePointManager checkCertificateRevocationList="true"/>-->
    </settings>
  </system.net>
  <dotNetOpenAuth>
    <!-- This is an optional configuration section where aspects of dotnetopenauth can be customized. -->
    <!-- For a complete set of configuration options see http://www.dotnetopenauth.net/developers/code-snippets/configuration-options/ -->
    <openid>
      <relyingParty>
        <security requireSsl="false" />
        <behaviors>
          <!-- The following OPTIONAL behavior allows RPs to use SREG only, but be compatible
                         with OPs that use Attribute Exchange (in various formats). -->
          <add type="DotNetOpenAuth.OpenId.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth" />
        </behaviors>
      </relyingParty>
    </openid>
    <messaging>
      <untrustedWebRequest>
        <whitelistHosts>
          <!-- Uncomment to enable communication with localhost (should generally not activate in production!) -->
          <!--<add name="localhost" />-->
        </whitelistHosts>
      </untrustedWebRequest>
    </messaging>
    <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
    <reporting enabled="true" />
  </dotNetOpenAuth>
</configuration>

UPDATE:

You could implement a custom resource retrieval provider:

public class CustomResourceProvider : IEmbeddedResourceRetrieval
{
    public Uri GetWebResourceUrl(Type someTypeInResourceAssembly, string manifestResourceName)
    {
        return new Uri("http://www.google.com");
    }
}

and then register it in web.config:

<dotNetOpenAuth>
    <webResourceUrlProvider type="AppName.CustomResourceProvider, AppName" />
    ...
</dotNetOpenAuth>

But I would recommend you using the openid-selector library for generating login forms.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Did you manage to get this working? I've created the Custom Resource Provider and added the registration in the web.config but the issue still occurs. – Jonathan Stowell Feb 22 '11 at 22:38
8

I came across this problem when I was trying to get the NerdDinner OpenID working for MVC3/razor. The solution that has worked for me is:

Create this class in your solution: (this was found in one of the NerdDinner builds - http://nerddinner.codeplex.com/SourceControl/changeset/view/55257#1328982 (thanks to JasonHaley) for some reason, this file isn't in the latest build for NerdDinner MVC3/Razor

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using DotNetOpenAuth;
namespace <Your App>.Services
{
    public class EmbeddedResourceUrlService : IEmbeddedResourceRetrieval
    {

        private static string pathFormat = "{0}/{1}/Resource/GetWebResourceUrl?assemblyName={2}&typeName={3}&resourceName={‌​4}";
        //private static string pathFormat = "{0}/Resource/GetWebResourceUrl";

        public Uri GetWebResourceUrl(Type someTypeInResourceAssembly, string manifestResourceName)
        {
            if (manifestResourceName.Contains("http"))
            {
                return new Uri(manifestResourceName);
            }
            else
            {
                var assembly = someTypeInResourceAssembly.Assembly;

                // HACK
                string completeUrl = HttpContext.Current.Request.Url.ToString();
                string host = completeUrl.Substring(0,
                    completeUrl.IndexOf(HttpContext.Current.Request.Url.AbsolutePath));

                var path = string.Format(pathFormat,
                            host,
                            HttpContext.Current.Request.ApplicationPath.Substring(1),
                            HttpUtility.UrlEncode(assembly.FullName),
                            HttpUtility.UrlEncode(someTypeInResourceAssembly.ToString()),
                            HttpUtility.UrlEncode(manifestResourceName));

                return new Uri(path);
            }
        }
    }
}

Then in your web.config, add this line:

<webResourceUrlProvider type="<Your App>.Services.EmbeddedResourceUrlService, <Your App>" />

just put in the DotNetOpenAuth section

you will also need this route set up: ( Html.OpenIdSelectorScripts helper method throwing NullReferenceException )

    routes.MapRoute(
        "OpenIdDiscover",
        "Auth/Discover"
    );
Community
  • 1
  • 1
Beno
  • 4,633
  • 1
  • 27
  • 26
  • 1
    NOTE: the formation of the URI will not work for application in their own folder under the root (and it might be a bit challenging for some to diagnose). – BrianCooksey Aug 30 '11 at 07:08
  • 3
    Use this for the path string: private static string pathFormat = "{0}/{1}/Resource/GetWebResourceUrl?assemblyName={2}&typeName={3}&resourceName={4}"; – BrianCooksey Aug 30 '11 at 07:09
  • 1
    and this to populate it: var path = string.Format(pathFormat, host, HttpContext.Current.Request.ApplicationPath.Substring(1), HttpUtility.UrlEncode(assembly.FullName), HttpUtility.UrlEncode(someTypeInResourceAssembly.ToString()), HttpUtility.UrlEncode(manifestResourceName)); – BrianCooksey Aug 30 '11 at 07:09
  • Otherwise DotNetOpenAuth will generate http://hostname/Resource/GetWebResourceUrl... instead of http://hostname/apppath/Resource/GetWebResourceUrl... – BrianCooksey Aug 30 '11 at 07:11
  • @BCooksey, I've applied your comments to the answer. Thanks. – Andrew Arnott Sep 07 '11 at 15:39