Как разрешить Dapper System.Data.DataException HResult = 0x80131501 InvalidCastException Неверное приведение из «System.String» в «System.Uri» - PullRequest
0 голосов
/ 21 января 2019

Недавно я произвел рефакторинг некоторого кода, который привел к изменению типа некоторых свойств объекта с System.String на System.URI. Названия рассматриваемых свойств содержали подстроку URI или URL, и статический анализатор кода SonarLint рекомендовал, чтобы код был реорганизован для использования типа System.URI вместо System.String для этих свойств, что делает смысл в нашем решении.

В этом проекте мы используем Dapper от StackExchange в качестве сверхбыстрого и легкого сопоставителя объектов, но после рефакторинга я начал получать эту ошибку при попытке извлечь данные из моего хранилища:

System.Data.DataException
  HResult=0x80131501
  Message=Error parsing column 5 (RequestUrl=https://www.myurl.com/api/wow - String)
  Source=Dapper
  StackTrace:
   at Dapper.SqlMapper.ThrowDataException(Exception ex, Int32 index, IDataReader reader, Object value) in C:\projects\dapper\Dapper\SqlMapper.cs:line 3609
   at Dapper.SqlMapper.<>c__DisplayClass156_0`8.<GenerateMapper>b__1(IDataReader r) in C:\projects\dapper\Dapper\SqlMapper.cs:line 1544
   at Dapper.SqlMapper.<MultiMapImpl>d__153`8.MoveNext() in C:\projects\dapper\Dapper\SqlMapper.cs:line 1444
   at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Dapper.SqlMapper.<MultiMapAsync>d__52`8.MoveNext() in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 949
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at My.Namespace.MyRepository.<GetAllRepositoryMethod>d__2.MoveNext() in C:\dev\repos\myproject\MyRepository.cs:line 59
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at My.Namespace.Program.CallerMethod(Object sender, ElapsedEventArgs e) in C:\dev\repos\myproject\Program.cs:line 109
   at System.Timers.Timer.MyTimerCallback(Object state)

Inner Exception 1:
InvalidCastException: Invalid cast from 'System.String' to 'System.Uri'.

Как обойти эту ошибку?

1 Ответ

0 голосов
/ 21 января 2019

Оказывается, что Dapper легко расширяется, и, объявив простой класс, который расширяет SqlMapper.TypeHandler<T>, вы можете определить отображение (TypeHandler) между типами System.String и System.URI и включить Dapper для выполнения приведения.

Вот как выглядит этот класс:

using System;
using System.Data;
using Dapper;

namespace My.Namespace.Data.DatabaseTools
{
    public class DapperUriTypeHandler : SqlMapper.TypeHandler<Uri>
    {
        public override void SetValue(IDbDataParameter parameter, Uri value)
        {
            parameter.Value = value.ToString();
        }

        public override Uri Parse(object value)
        {
            return new Uri((string)value);
        }
    }    
}

После того как вы объявили отображение, вы можете сообщить об этом Dapper, вызвав метод SqlMapper.AddTypeHandler и предоставив экземпляр вашего класса обработчика пользовательского типа в качестве параметра, например так:

SqlMapper.AddTypeHandler(new DapperUriTypeHandler());

Лучшее место для вызова SqlMapper.AddTypeHandler - это где-то в вашей загрузочной конфигурации, чтобы обработчик типов был известен Dapper на раннем этапе выполнения вашего приложения или службы.

Надеюсь, что это поможет другим членам сообщества решить подобные проблемы с Dapper и быстро вводить типы в будущем!

...