2015-03-09 4 views
2

У меня есть объект данных, где клиенты могут прикреплять файлы. Когда клиент нажимает кнопку сохранения, я лениво загружаю содержимое файла (File.ReadAllBytes(path)) и отправляю его из клиентского приложения в серверное приложение.Как бороться с исключениями при сериализации в вызове WCF

[Browsable(false)] 
    [ProtoMember(4)] 
    public byte[] BinaryData 
    { 
     get 
     { 
      if (_binaryData == null && !string.IsNullOrEmpty(FilePath)) 
      { 
       _binaryData = File.ReadAllBytes(FilePath); 
      } 
      return _binaryData; 
     } 
     private set 
     { 
      _binaryData = value; 
     } 
    } 

Предположим, что файл является файлом Excel, и клиент все еще открыт. Затем вызывается исключение IO, которое файл по-прежнему заблокирован другим приложением.

Это приводит к поломке моего канала - что совершенно неприемлемо.

Есть ли способ обойти это? Я даже попробовал FaultContract, но безрезультатно. Этого следовало ожидать, потому что я даже не получаю от клиента сервер.

[OperationContract] 
    [FaultContract(typeof(ExceptionDetail))] 
    T Save(T dataObject, Guid clientGuid); 

Конечно, я могу поймать это исключение, отправьте сообщение на сервер и бросить FaultException на стороне сервера - но мне не нравится эта идея.

Я также могу проверить объект данных на стороне клиента перед отправкой, но мне тоже не нравится эта идея.

Есть ли возможность отменить сообщение, не приводя к неисправности канала?

Окружающая среда:

  • .net 4.0 с VS 2010
  • CompressionMessageEncoderFactory с Protobuf внутрисетевые сериализации

CallStack (части):

mscorlib.dll! System.IO .__ Error.WinIOError (int errorCode = -2147024864, строка MaybeFullPath = "C: \ XXX.xls") + 0x321 байт
mscorlib.dll! System.IO.FileStream.Init (строковый путь, режим System.IO.FileMode, System.IO.FileAccess access = чтение, int rights, bool useRights = false, общий доступ к System.IO.FileShare, int bufferSize = 4096, параметры System.IO.FileOptions, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs, строка msgPath, bool bFromProxy, bool useLongPath) + 0x477 байт
mscorlib.dll! System.IO.FileStream.FileStream (строка пути, System. Режим IO.FileMode, доступ к System.IO.FileAccess, общий доступ к System.IO.FileShare) + 0x54 байта mscorlib.dll! System.IO.File.ReadAllBytes (строка) + 0x3b байтов
AB.XYZ.DataModel.dll ! AB.XYZ.DataModel.FileContent.BinaryData.get() Строка 83 + 0x19 байт C# AB.XYZ.DataModel.dll! AB.XYZ.DataModel.FileContent.OnSerializing (System.Runtime.Serialization. StreamingContext с = {System.Runtime.Serialization.StreamingContext}) Строка 123 + 0x43 байт C# [Lightweight Функция]
.... System.Runtime.Serialization.dll! System.Runtime.Serialization.XmlObjectSerializer.WriteObject (System .Xml.XmlDictionaryWriter writer, object graph) + 0x2d байты .... System.ServiceModel.dll! System.ServiceModel.Channels.BinaryMessageEncoderFactory.BinaryMessageEncoder.WriteMessage (System.ServiceModel.Channels.Message message = {System.ServiceModel. Dispatcher.OperationFormatter.OperationFormatterMessage}, int maxMessageSize = 2147483647, System.ServiceModel.Channels.BufferManager bufferManager = {System.ServiceModel.Channels.BufferManager.WrappingBufferManager}, int messageOffset = 5) + 0x452 bytes
AB.XYZ.WCF.Common.dll! AB.XYZ.WCF.Common.dll! AB.XYZ.WCF.Common.Encoder.CompressionMessageEncoderFactory.CompressionMessageEncoder.WriteMessage (System.ServiceModel.Channels.Message message = {System .ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage}, int maxMessageSize = 2147483647, System.ServiceModel.Channels.BufferManager bufferManager = {System.ServiceModel.Channels.BufferManager.WrappingBufferManager}, int messageOffset = 6) Строка 236 + 0x2b байтов C# .. .. mscorlib.dll! System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke (ref System.Runtime.Remoting.Proxies.MessageData msgData, int type = 1) + 0xee bytes
AB.XYZ.WCF.Client.dll ! AB.XYZ.WCF.Client.WCFDataStore.Save.AnonymousMethod__0() Строка 28 + 0x94 байт C#

+0

Вы в конечном итоге решили эту проблему? –

+0

@TomRedfern: не совсем. Я изменил поведение. Поэтому, когда выбран файл, я получаю его содержимое немедленно (и сохраняю его в памяти). Не то, что я имел в виду, но его работа и была наименее инвазивным способом. – toATwork

+0

Спасибо за ответ. Если вы прочитаете первые строки моего ответа ниже, это именно то, что я рекомендовал - * Если вы не хотите этого поведения, загрузите файл excel в память, прежде чем открывать клиентский канал wcf. * –

ответ

1

Это приводит к поломке моего канала - что совершенно неприемлемо.

Если это неприемлемо для вас, прекратите это делать.

Если вы не хотите этого поведения, загрузите файл excel в память, прежде чем открывать клиентский канал wcf.

Я даже попробовал FaultContract, но безрезультатно

Это происходит потому, что контракты неисправностей WCF предназначены для обработки ошибок на стороне сервера.

Я также могу проверить объект данных на стороне клиента перед отправкой, но Мне тоже не нравится эта идея.

Если вы пишете код, который может создавать данные, которые в нерабочем состоянии, и поэтому терпит неудачу во время сериализации, и вы не хотите проверять состояние данных, а затем ожидает рамки, чтобы иметь какой-то встроенный способ справиться с этим - это признак того, что вы не понимаете рамки.

Структура моих объектов данных динамически - клиент может настроить его. Теоретически любое свойство может выдавать исключение

Как выглядит ваш контракт на операцию? Предоставляет ли он аргумент объекта типа? Если это так, для WCF это не так. Если вам нужна общая операция службы, которая может буквально обрабатывать любой тип, который вы передаете, тогда вам будет лучше всего using messages directly.

+0

Файл Excel - это всего лишь пример. Структура моих объектов данных динамически - клиент может ее настроить. Теоретически любое свойство может вызывать исключение. Единственный способ добиться того, что вы предлагаете, - это сериализовать объект перед его отправкой (который затем будет сериализовать его снова). Этого я также хочу избежать. – toATwork

+0

@toATwork Я обновил свой ответ –