Что связывает ApplicationUser с таблицей aspnetusers в Database First?

У меня есть модель EDMX для базы данных в отдельной библиотеке (например, Common.Feedback.Data), которая включает в себя таблицу AspNetUser и связанные с ней таблицы Identity Framework (извлеченные из другой существующей, работающей базы данных/приложения).

Я обновил строку подключения ApplicationDbContext, чтобы она указывала на новую модель и новое подключение к базе данных:

using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;

namespace Feedback.MvcApplication.Models
{
    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.

    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("FeedbackEntities", throwIfV1Schema: false)
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }
}

Строка подключения в файле web.config включает полный путь к сборке, и с этой ссылкой все в порядке:

<add name="FeedbackEntities" 
     connectionString="metadata=res://Common.Feedback.Data/FeedbackModel.csdl|res://Common.Feedback.Data/FeedbackModel.ssdl|res://Common.Feedback.Data/FeedbackModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=mydatabase.database.windows.net;initial catalog=Feedback;persist security info=True;user id=LeaveFeedbackuser@mydatabase;password=mypassword;MultipleActiveResultSets=True;App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

Во время выполнения любой доступ к логину приводит к следующей ошибке:

«Тип объекта ApplicationUser не является частью модели для текущего контекста»

Все ссылки, которые я пробовал, связанные с этой ошибкой, обычно включают способы обновления миграции.

Я не могу включить миграцию, так как это первая установка EDMX, но я предполагаю, что существует связь между объектом ApplicationUser и таблицей aspnetusers "где-то" за кулисами.

Есть ли у кого-нибудь здесь четкое представление о том, как класс ApplicationUser сопоставляется с таблицей aspnetusers и из нее во время выполнения, и объясняет, как заставить мой код работать с базой данных?

Воспроизведение шагов

  • Создайте новое веб-приложение MVC с помощью VS 2013.
  • Обновите все пакеты NuGet до последней версии.
  • Возьмите существующую базу данных SQL с таблицами Identity Framework и скопируйте ее в новую таблицу (удалив все несвязанные таблицы).
  • Добавить новые таблицы для проекта
  • Создайте библиотеку классов для хранения моделей данных (например, Common.Feedback.Data)
  • Добавьте модель данных Edmx в библиотеку на основе базы данных, созданной ранее.
  • Измените строку подключения, чтобы полностью квалифицировать сборку (не res://*/)
  • Измените имя строки подключения в IdentityModel.cs, чтобы оно соответствовало имени строки подключения в конфигурации.
  • Скопируйте строку подключения из app.config библиотеки в web.config веб-проекта.
  • Попробуйте войти, и вы столкнетесь с упомянутой ошибкой

Обновление:

Основываясь на случайном сообщении, я изменил свою строку подключения, чтобы она соответствовала обычному SQL-соединению, которое Identity Framework настроено для использования по умолчанию (и с использованием клиента Sql):

<add name="FeedbackSql" 
     connectionString="data source=mydatabase.database.windows.net;initial catalog=Feedback;persist security info=True;user id=LeaveFeedbackuser@mydatabase;password=mypassword;MultipleActiveResultSets=True;App=EntityFramework" 
     providerName="System.Data.SqlClient" />

и изменен на настройку, чтобы использовать это новое соединение:

   public ApplicationDbContext()
        : base("FeedbackSql", throwIfV1Schema: false)
    {
    }

Как ни странно, ошибка меняется на:

Магическое число в заголовке GZip неверно. Убедитесь, что вы передаете поток GZip.

Я думаю, что первоначальное изменение поставщика SqlClient верно, поэтому эта новая ошибка может быть связана с использованием базы данных Azure по этому соединению. Я открыт для предложений о том, что попробовать дальше.

Обновлен файл web.config на основе предложения @rism и эта ссылка (но ошибка GZip сохраняется):

  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
      <parameters>
        <!--<parameter value="mssqllocaldb" />-->
        <parameter value="data source=mydatabase.database.windows.net;initial catalog=Feedback;persist security info=True;user id=myuserid;password=mypassword;MultipleActiveResultSets=True;App=EntityFramework" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>

Опять же, основываясь на советах @rism, я также попробовал эту версию (но ошибка GZip сохраняется):

  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v12.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>

Новое обновление:

Я создал совершенно новое веб-приложение со стандартной опцией user-security. Я также создал пустую базу данных в Azure.

Я ничего не сделал, но изменил строку подключения по умолчанию на это:

  <connectionStrings>
    <add name="DefaultConnection" 
         connectionString="data source=mydatabase.database.windows.net;initial catalog=Feedback;persist security info=True;user id=LeaveFeedbackuser;password=mypassword;MultipleActiveResultSets=True;App=EntityFramework"
         providerName="System.Data.SqlClient" />
  </connectionStrings>

и фабрика соединений по умолчанию для этого:

  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v12.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>

При попытке войти получаю следующую ошибку:

Магическое число в заголовке GZip неверно. Убедитесь, что вы передаете поток GZip. Описание: во время выполнения текущего веб-запроса возникло необработанное исключение. Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении: System.IO.InvalidDataException: неверное магическое число в заголовке GZip. Убедитесь, что вы передаете поток GZip.

Ошибка источника:

Строка 153: { Строка 154: var user = new ApplicationUser {Имя пользователя = model.Email, Email = model.Email}; Строка 155: var result = await UserManager.CreateAsync(user, model.Password); Строка 156: if (result.Succeeded) Строка 157: {


person Gone Coding    schedule 27.01.2015    source источник
comment
Если вы идете по пути решения, ориентированного на БД, нет причин придерживаться ApplicationDbContext. Вы можете просто удалить весь этот мусор, иметь свой собственный DbContext и избавить себя от головной боли.   -  person James Sampica    schedule 28.01.2015
comment
Вы показали только конструктор для ApplicationDbContext(), можете ли вы показать весь класс. Также какую версию Identity вы используете? Версия 1.0 сильно отличается от версии 2. Сопоставления между классами и таблицами выполняются через подклассы EntityTypeConfiguration, в которых вы настраиваете аспекты модели, такие как сопоставление ссылочной целостности, кардинальности и т. д. Если вы использовали Fluent Api в TspIdentityMap: EntityTypeConfiguration‹TspIdentity › вы бы сделали такое утверждение.ToTable(AspNetUsers); то есть вы сопоставляете объект класса кода TspIdentity с таблицей db.   -  person rism    schedule 28.01.2015
comment
Причина, по которой я хочу увидеть весь ваш ApplicationDbContext, заключается в том, что сообщение читается для меня так, как будто у вас нет DbSet‹ApplicationUser› в вашем контексте, хотя обычно это вызывает ошибку компилятора... но тогда вы смешали и сопоставили биты, так что давайте посмотрим все равно. Также убедитесь, что вы используете одну и ту же версию Identity во всех проектах.   -  person rism    schedule 28.01.2015
comment
@rism: я должен был сказать, что все готово к использованию. Скаффолдинг Visual Studio 2013 + MVC5 Razor с последними версиями всего. В настоящее время это всего лишь проект с голыми костями, пока я не решу эту проблему.   -  person Gone Coding    schedule 28.01.2015
comment
В web.config проекта по умолчанию ‹entityFramework› ‹defaultConnectionFactory будет настроен на использование LocalDb. Вы обновили их для использования SqlServer? А можете показать нам трассировку стека из YSOD?   -  person rism    schedule 29.01.2015
comment
@rism: вы были правы, что он был установлен как локальный db для defaultConnectionFactory. Я изменил его, чтобы он соответствовал желаемому типу соединения SQL, но все еще получаю сообщение об ошибке GZip, упомянутое в обновлении.   -  person Gone Coding    schedule 29.01.2015
comment
@TrueBlueAussie Обычно вы сохраняете строку подключения как есть и обновляете этот раздел следующим образом: ‹entityFramework› ‹defaultConnectionFactory type=System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework› ‹parameters› ‹parameter value=v12.0 /› ‹/parameters› ‹/defaultConnectionFactory› ‹providers› ‹provider invariantName=System.Data.SqlClient type=System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer /› ‹/providers› ‹/entityFramework›   -  person rism    schedule 29.01.2015
comment
@rism: Спасибо за упрощение. Все еще получаю сообщение об ошибке GZip. Я подумал: поскольку в коде указано конкретное имя соединения, я сомневаюсь, что DefaultConnectionFactory вообще используется.   -  person Gone Coding    schedule 29.01.2015
comment
@TrueBlueAussie Нет, это не будет использоваться в рабочем приложении с предоставленной строкой подключения, на самом деле это действительно только для кода в первую очередь, но поскольку вы явно упомянули ApplicationDbContext(), который является контекстом, сгенерированным в первую очередь кодом (из пакета AspIdentity nuget) Я хотел, чтобы это имело какое-либо значение, но, похоже, нет. Что произойдет, если вы удалите ApplicationDbContext, а затем очистите ошибки компиляции, указав все ссылки на ApplicationDbContext на любой DbContext, созданный EDMX. По сути, мне кажется, что вы сначала одной ногой в коде, а другой в DbFirst.   -  person rism    schedule 29.01.2015
comment
Я уверен, что если бы вы загрузили ExpressProfiler из CodePlex, вы бы увидели, что запрос к базе данных вообще не отправляется, поэтому сопоставление вообще не будет проблемой с точки зрения имени класса кода и имени таблицы базы данных, которое просто использует соглашение о том же Имя в этом случае. т. е. явное отображение не происходит.   -  person rism    schedule 29.01.2015
comment
@rism: я создал новый вопрос о проблеме с подключением, поскольку я отделил его от исходной проблемы с новым воспроизведением. Заголовок stackoverflow.com/questions/28227020/ Пожалуйста, продолжайте, поскольку я нашел ответ на исходную проблему с заголовком (ниже) .   -  person Gone Coding    schedule 30.01.2015


Ответы (1)


Первоначальный вопрос был о том, как OWIN сопоставляет класс ApplicationUser с таблицей AspNetUsers.

Я декомпилировал dll Identity Framework с помощью DotPeek и обнаружил, что имя таблицы «AspNetUsers» просто жестко встроено в код метода OnModelCreating. например

 protected virtual void OnModelCreating(DbModelBuilder modelBuilder)
    {
      if (modelBuilder == null)
        throw new ArgumentNullException("modelBuilder");
        EntityTypeConfiguration<TUser> typeConfiguration1 = ((EntityTypeConfiguration<TUser>) modelBuilder.Entity<TUser>())
        .ToTable("AspNetUsers");

Этот код использует отражение для создания списка имен полей из свойств в ApplicationUser. Он проверяет наличие всех этих имен полей с помощью простого SQL-запроса (системной таблицы, содержащей все имена полей) и подтверждает, что все они присутствуют.

Остальное — простое сопоставление имен/значений с использованием сконструированных SQL-запросов.

Что касается другой части проблемы, подключения к базе данных, я создал новый вопрос, поскольку он а) не связан с заголовком этого вопроса и б) сводит меня с ума! Новый вопрос Почему я получаю Магический номер в заголовке GZip неверен. ошибка при использовании аутентификации OWIN для Azure SQL

person Gone Coding    schedule 30.01.2015