-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #300 from Lombiq/issue/OFFI-149
OFFI-149: HttpContent and ZipArchive extensions, UserReadableException
- Loading branch information
Showing
9 changed files
with
194 additions
and
9 deletions.
There are no files selected for viewing
This file contains 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 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
65 changes: 65 additions & 0 deletions
65
Lombiq.HelpfulLibraries.AspNetCore/Extensions/HttpContentExtensions.cs
This file contains 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,65 @@ | ||
using Microsoft.AspNetCore.StaticFiles; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.IO; | ||
using System.Net.Http.Headers; | ||
using System.Net.Mime; | ||
using System.Text; | ||
|
||
namespace System.Net.Http; | ||
|
||
public static class HttpContentExtensions | ||
{ | ||
/// <summary> | ||
/// Attaches a new file field to this web request content. | ||
/// </summary> | ||
/// <param name="form">The form content of the request.</param> | ||
/// <param name="name">The name of the field.</param> | ||
/// <param name="fileName">The name and extension of the file being uploaded.</param> | ||
/// <param name="mediaType">The file's MIME type (use <see cref="MediaTypeNames"/>).</param> | ||
/// <param name="content">The content of the file.</param> | ||
[SuppressMessage( | ||
"Reliability", | ||
"CA2000:Dispose objects before losing scope", | ||
Justification = "The parent form should be disposed instead.")] | ||
public static void AddFile( | ||
this MultipartFormDataContent form, | ||
string name, | ||
string fileName, | ||
string mediaType, | ||
byte[] content) | ||
{ | ||
var xml = new ByteArrayContent(content); | ||
xml.Headers.ContentType = MediaTypeHeaderValue.Parse(mediaType); | ||
form.Add(xml, name, fileName); | ||
} | ||
|
||
/// <inheritdoc cref="AddFile(System.Net.Http.MultipartFormDataContent,string,string,string,byte[])"/> | ||
/// <param name="content">The content of the file. It will be encoded as UTF-8.</param> | ||
public static void AddFile( | ||
this MultipartFormDataContent form, | ||
string name, | ||
string fileName, | ||
string mediaType, | ||
string content) => | ||
form.AddFile(name, fileName, mediaType, Encoding.UTF8.GetBytes(content)); | ||
|
||
/// <summary> | ||
/// Adds a file from disk. The file name is derived from <paramref name="path"/> and if <paramref name="mediaType"/> | ||
/// is <see langword="null"/>, then it's guessed from the file name as well. | ||
/// </summary> | ||
public static void AddLocalFile( | ||
this MultipartFormDataContent form, | ||
string name, | ||
string path, | ||
string mediaType = null) | ||
{ | ||
if (string.IsNullOrEmpty(mediaType) && | ||
!new FileExtensionContentTypeProvider().TryGetContentType(path, out mediaType)) | ||
{ | ||
// Fall back to a media type that indicates unspecified binary data. | ||
mediaType = MediaTypeNames.Application.Octet; | ||
} | ||
|
||
form.AddFile(name, Path.GetFileName(path), mediaType, File.ReadAllBytes(path)); | ||
} | ||
} |
This file contains 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,3 @@ | ||
# Lombiq Helpful Libraries - Common - Exceptions | ||
|
||
- `UserReadableException`: An exception whose message is safe to display to the end user. |
55 changes: 55 additions & 0 deletions
55
Lombiq.HelpfulLibraries.Common/Exceptions/UserReadableException.cs
This file contains 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,55 @@ | ||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace Lombiq.HelpfulLibraries.Common.Exceptions; | ||
|
||
/// <summary> | ||
/// An exception whose message is safe to display to the end user of a desktop or command line application. | ||
/// </summary> | ||
/// <remarks><para> | ||
/// In case of web application, use <c>Lombiq.HelpfulLibraries.AspNetCore</c>'s <c>FrontendException</c> instead. | ||
/// </para></remarks> | ||
public class UserReadableException : Exception | ||
{ | ||
/// <summary> | ||
/// Gets the list of error messages that can be displayed to the user. | ||
/// </summary> | ||
public IReadOnlyList<string> Messages { get; } = []; | ||
|
||
public UserReadableException(ICollection<string> messages, Exception? innerException = null) | ||
: base(string.Join(Environment.NewLine, messages), innerException) => | ||
Messages = [.. messages]; | ||
|
||
public UserReadableException(string message) | ||
: this([message]) | ||
{ | ||
} | ||
|
||
public UserReadableException() | ||
{ | ||
} | ||
|
||
public UserReadableException(string message, Exception? innerException) | ||
: this([message], innerException) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// If the provided collection of <paramref name="errors"/> is not empty, it throws an exception with the included | ||
/// texts. | ||
/// </summary> | ||
/// <param name="errors">The possible collection of error texts.</param> | ||
/// <exception cref="UserReadableException">The non-empty error messages from <paramref name="errors"/>.</exception> | ||
public static void ThrowIfAny(ICollection<string>? errors) | ||
{ | ||
errors = errors?.WhereNot(string.IsNullOrWhiteSpace).ToList(); | ||
|
||
if (errors == null || errors.Count == 0) return; | ||
if (errors.Count == 1) throw new UserReadableException(errors.Single()); | ||
|
||
throw new UserReadableException(errors); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
Lombiq.HelpfulLibraries.Common/Extensions/ZipArchiveExtensions.cs
This file contains 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,35 @@ | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace System.IO.Compression; | ||
|
||
public static class ZipArchiveExtensions | ||
{ | ||
/// <summary> | ||
/// Creates a new text file in <paramref name="zip"/> and writes the <paramref name="lines"/> into it. | ||
/// </summary> | ||
public static async Task CreateTextEntryAsync(this ZipArchive zip, string entryName, IEnumerable<string> lines) | ||
{ | ||
await using var writer = new StreamWriter(zip.CreateEntry(entryName).Open()); | ||
|
||
foreach (var line in lines) | ||
{ | ||
await writer.WriteLineAsync(line); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates a new text file in <paramref name="zip"/> and writes the <paramref name="text"/> into it. | ||
/// </summary> | ||
public static Task CreateTextEntryAsync(this ZipArchive zip, string entryName, string text) => | ||
zip.CreateTextEntryAsync(entryName, [text]); | ||
|
||
/// <summary> | ||
/// Creates a new binary file in <paramref name="zip"/> and writes the <paramref name="data"/> into it. | ||
/// </summary> | ||
public static async Task CreateBinaryEntryAsync(this ZipArchive zip, string entryName, ReadOnlyMemory<byte> data) | ||
{ | ||
await using var stream = zip.CreateEntry(entryName).Open(); | ||
await stream.WriteAsync(data); | ||
} | ||
} |
This file contains 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 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 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