- 
                Notifications
    You must be signed in to change notification settings 
- Fork 22
Stream Correspondence attachments to support large file upload #1413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Open
      
      
            Ceredron
  wants to merge
  40
  commits into
  Altinn:main
  
    
      
        
          
  
    
      Choose a base branch
      
     
    
      
        
      
      
        
          
          
        
        
          
            
              
              
              
  
           
        
        
          
            
              
              
           
        
       
     
  
        
          
            
          
            
          
        
       
    
      
from
Ceredron:feat/streamed-correspondence-upload
  
      
      
   
  
    
  
  
  
 
  
      
    base: main
Could not load branches
            
              
  
    Branch not found: {{ refName }}
  
            
                
      Loading
              
            Could not load tags
            
            
              Nothing to show
            
              
  
            
                
      Loading
              
            Are you sure you want to change the base?
            Some commits from the old base branch may be removed from the timeline,
            and old review comments may become outdated.
          
          
      
        
          +321
        
        
          −63
        
        
          
        
      
    
  
  
     Open
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            40 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      28fb6c6
              
                Stream Correspondence attachments to support large file upload
              
              
                Ceredron c8d5744
              
                Fix build
              
              
                Ceredron 1d1d245
              
                Fix build
              
              
                Ceredron 0a37109
              
                Revert "Fix build"
              
              
                Ceredron 6fc12c1
              
                Revert "Fix build"
              
              
                Ceredron 6f1e076
              
                Fix tests
              
              
                Ceredron 29fb277
              
                Typo
              
              
                Ceredron eb5cb3a
              
                Fix more tests
              
              
                Ceredron c8d453d
              
                Merge branch 'main' into feat/streamed-correspondence-upload
              
              
                Ceredron fb8f85a
              
                Formatting
              
              
                Ceredron 61805b8
              
                Merge branch 'feat/streamed-correspondence-upload' of https://github.…
              
              
                Ceredron d3a6ad1
              
                Break API
              
              
                Ceredron 33dcf0b
              
                Expanded interface to include stream implementation
              
              
                Ceredron 4af8625
              
                Break
              
              
                Ceredron 2dccc09
              
                Tempfix for testing streaming response
              
              
                Ceredron ad99a4d
              
                Only stream when necessary
              
              
                Ceredron 96211e1
              
                "Non-breaking" version
              
              
                Ceredron 55b8fde
              
                Fix build
              
              
                Ceredron 4165255
              
                Bang some tests
              
              
                Ceredron e6a0504
              
                Re-factor to try to break less
              
              
                Ceredron 460e830
              
                Use ResponseStreamWrapper to ensure correct disposal of response mess…
              
              
                Ceredron 7c7031d
              
                Xml docs
              
              
                Ceredron cc5de34
              
                Streams needs to be suffixed with Stream
              
              
                Ceredron 8821d7b
              
                Small fixes
              
              
                Ceredron f30c680
              
                More fix
              
              
                Ceredron 574f29a
              
                Internalize 'ResponseWrapperStream',  disposal, extend XML docs for c…
              
              
                martinothamar dbd86ab
              
                Experiment to use REST instead of Form endpoints
              
              
                Ceredron 723e980
              
                Formatting etc
              
              
                Ceredron 527bf2c
              
                API for experiment
              
              
                Ceredron 351cddd
              
                Revert "API for experiment"
              
              
                Ceredron dc7485a
              
                Revert "Formatting etc"
              
              
                Ceredron 351ad4f
              
                Revert "Experiment to use REST instead of Form endpoints"
              
              
                Ceredron d600d0a
              
                Merge branch 'main' into feat/streamed-correspondence-upload
              
              
                martinothamar 0379ca8
              
                New experiment
              
              
                Ceredron f8ae91f
              
                Merge branch 'feat/streamed-correspondence-upload' of https://github.…
              
              
                Ceredron 2204363
              
                Remove usings
              
              
                Ceredron 29a992a
              
                Revert "Remove usings"
              
              
                Ceredron d41e3f5
              
                Revert "New experiment"
              
              
                Ceredron 49cac69
              
                Disposals, update integration test snapshots
              
              
                martinothamar 1561d72
              
                Merge branch 'main' into feat/streamed-correspondence-upload
              
              
                martinothamar File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
        
          
          
            25 changes: 25 additions & 0 deletions
          
          25 
        
  src/Altinn.App.Core/Features/Correspondence/Models/CorrespondenceAttachmentInMemory.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| namespace Altinn.App.Core.Features.Correspondence.Models; | ||
|  | ||
| /// <summary> | ||
| /// Represents an attachment to a correspondence. | ||
| /// </summary> | ||
| public record CorrespondenceAttachmentInMemory : CorrespondenceAttachment | ||
| { | ||
| /// <summary> | ||
| /// The data content. | ||
| /// </summary> | ||
| public required ReadOnlyMemory<byte> Data { get; init; } | ||
|  | ||
| internal override void Serialise(MultipartFormDataContent content, int index, string? filenameOverride = null) | ||
| { | ||
| const string typePrefix = "Correspondence.Content.Attachments"; | ||
| string prefix = $"{typePrefix}[{index}]"; | ||
| string actualFilename = filenameOverride ?? Filename; | ||
|  | ||
| AddRequired(content, actualFilename, $"{prefix}.Filename"); | ||
| AddRequired(content, SendersReference, $"{prefix}.SendersReference"); | ||
| AddRequired(content, DataLocationType.ToString(), $"{prefix}.DataLocationType"); | ||
| AddRequired(content, Data, "Attachments", actualFilename); | ||
| AddIfNotNull(content, IsEncrypted?.ToString(), $"{prefix}.IsEncrypted"); | ||
| } | ||
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
        
          
          
            32 changes: 32 additions & 0 deletions
          
          32 
        
  src/Altinn.App.Core/Features/Correspondence/Models/CorrespondenceStreamedAttachment.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| namespace Altinn.App.Core.Features.Correspondence.Models; | ||
|  | ||
| /// <summary> | ||
| /// Represents an attachment to a correspondence with streaming data support. | ||
| /// Inherits from CorrespondenceAttachment and provides a Stream-based data property. | ||
| /// Is more efficient if the attachment is large in size. | ||
| /// The stream must be open (not disposed) until the correspondence is sent. | ||
| /// The caller is responsible for disposing the stream after the correspondence has been sent. | ||
| /// </summary> | ||
| public record CorrespondenceStreamedAttachment : CorrespondenceAttachment | ||
| { | ||
| /// <summary> | ||
| /// The data content as a stream. | ||
| /// Is more efficient if the attachment is large in size. | ||
| /// The stream must be open (not disposed) until the correspondence is sent. | ||
| /// The caller is responsible for disposing the stream after the correspondence has been sent. | ||
| /// </summary> | ||
| public required Stream Data { get; init; } | ||
|  | ||
| internal override void Serialise(MultipartFormDataContent content, int index, string? filenameOverride = null) | ||
| { | ||
| const string typePrefix = "Correspondence.Content.Attachments"; | ||
| string prefix = $"{typePrefix}[{index}]"; | ||
| string actualFilename = filenameOverride ?? Filename; | ||
|  | ||
| AddRequired(content, actualFilename, $"{prefix}.Filename"); | ||
| AddRequired(content, SendersReference, $"{prefix}.SendersReference"); | ||
| AddRequired(content, DataLocationType.ToString(), $"{prefix}.DataLocationType"); | ||
| AddRequired(content, Data, "Attachments", actualFilename); | ||
| AddIfNotNull(content, IsEncrypted?.ToString(), $"{prefix}.IsEncrypted"); | ||
| } | ||
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| namespace Altinn.App.Core.Helpers; | ||
|  | ||
| /// <summary> | ||
| /// A wrapper stream that ensures proper disposal of an HttpResponseMessage along with its content stream. | ||
| /// </summary> | ||
| internal sealed class ResponseWrapperStream : Stream | ||
| { | ||
| private readonly HttpResponseMessage _response; | ||
| private readonly Stream _innerStream; | ||
|  | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="ResponseWrapperStream"/> class. | ||
| /// </summary> | ||
| /// <param name="response">The HTTP response message to be disposed when the stream is disposed.</param> | ||
| /// <param name="innerStream">The inner stream to wrap and delegate operations to.</param> | ||
| public ResponseWrapperStream(HttpResponseMessage response, Stream innerStream) | ||
| { | ||
| _response = response; | ||
| _innerStream = innerStream; | ||
| } | ||
|  | ||
| /// <summary> | ||
| /// Releases the unmanaged resources used by the <see cref="ResponseWrapperStream"/> and optionally releases the managed resources. | ||
| /// </summary> | ||
| /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> | ||
| protected override void Dispose(bool disposing) | ||
| { | ||
| if (disposing) | ||
| { | ||
| _response?.Dispose(); // This will also dispose the inner stream | ||
| } | ||
| base.Dispose(disposing); | ||
| } | ||
|  | ||
| // Delegate all Stream operations to _innerStream | ||
|  | ||
| /// <summary> | ||
| /// Gets a value indicating whether the current stream supports reading. | ||
| /// </summary> | ||
| public override bool CanRead => _innerStream.CanRead; | ||
|  | ||
| /// <summary> | ||
| /// Gets a value indicating whether the current stream supports seeking. | ||
| /// </summary> | ||
| public override bool CanSeek => _innerStream.CanSeek; | ||
|  | ||
| /// <summary> | ||
| /// Gets a value indicating whether the current stream supports writing. | ||
| /// </summary> | ||
| public override bool CanWrite => _innerStream.CanWrite; | ||
|  | ||
| /// <summary> | ||
| /// Gets the length in bytes of the stream. | ||
| /// </summary> | ||
| /// <exception cref="NotSupportedException">The stream does not support seeking.</exception> | ||
| public override long Length => _innerStream.Length; | ||
|  | ||
| /// <summary> | ||
| /// Gets or sets the position within the current stream. | ||
| /// </summary> | ||
| /// <exception cref="NotSupportedException">The stream does not support seeking.</exception> | ||
| public override long Position | ||
| { | ||
| get => _innerStream.Position; | ||
| set => _innerStream.Position = value; | ||
| } | ||
|  | ||
| /// <summary> | ||
| /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. | ||
| /// </summary> | ||
| public override void Flush() => _innerStream.Flush(); | ||
|  | ||
| /// <summary> | ||
| /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. | ||
| /// </summary> | ||
| /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param> | ||
| /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param> | ||
| /// <param name="count">The maximum number of bytes to be read from the current stream.</param> | ||
| /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns> | ||
| /// <exception cref="ArgumentNullException">buffer is null.</exception> | ||
| /// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception> | ||
| /// <exception cref="ArgumentException">The sum of offset and count is larger than the buffer length.</exception> | ||
| /// <exception cref="NotSupportedException">The stream does not support reading.</exception> | ||
| public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count); | ||
|  | ||
| /// <summary> | ||
| /// Sets the position within the current stream. | ||
| /// </summary> | ||
| /// <param name="offset">A byte offset relative to the origin parameter.</param> | ||
| /// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param> | ||
| /// <returns>The new position within the current stream.</returns> | ||
| /// <exception cref="NotSupportedException">The stream does not support seeking.</exception> | ||
| public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin); | ||
|  | ||
| /// <summary> | ||
| /// Sets the length of the current stream. | ||
| /// </summary> | ||
| /// <param name="value">The desired length of the current stream in bytes.</param> | ||
| /// <exception cref="NotSupportedException">The stream does not support both writing and seeking.</exception> | ||
| /// <exception cref="ArgumentOutOfRangeException">value is negative.</exception> | ||
| public override void SetLength(long value) => _innerStream.SetLength(value); | ||
|  | ||
| /// <summary> | ||
| /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. | ||
| /// </summary> | ||
| /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param> | ||
| /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param> | ||
| /// <param name="count">The number of bytes to be written to the current stream.</param> | ||
| /// <exception cref="ArgumentNullException">buffer is null.</exception> | ||
| /// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception> | ||
| /// <exception cref="ArgumentException">The sum of offset and count is greater than the buffer length.</exception> | ||
| /// <exception cref="NotSupportedException">The stream does not support writing.</exception> | ||
| public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count); | ||
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
      
      Oops, something went wrong.
        
    
  
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.