Skip to content

Commit 7c72f9b

Browse files
Add support to show custom error message
1 parent 362c0b1 commit 7c72f9b

File tree

8 files changed

+164
-9
lines changed

8 files changed

+164
-9
lines changed
73.2 KB
Loading

src/GroupDocs.Viewer.UI.API/Controllers/ViewerController.cs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class ViewerController : ControllerBase
2424
private readonly IFileStorage _fileStorage;
2525
private readonly IFileNameResolver _fileNameResolver;
2626
private readonly ISearchTermResolver _searchTermResolver;
27+
private readonly IErrorMessageProvider _errorMessageProvider;
2728
private readonly IApiUrlBuilder _apiUrlBuilder;
2829
private readonly ILogger<ViewerController> _logger;
2930
private readonly Config _config;
@@ -33,13 +34,15 @@ public ViewerController(
3334
IFileStorage fileStorage,
3435
IFileNameResolver fileNameResolver,
3536
ISearchTermResolver searchTermResolver,
37+
IErrorMessageProvider errorMessageProvider,
3638
IOptions<Config> config,
3739
IApiUrlBuilder apiUrlBuilder,
3840
ILogger<ViewerController> logger)
3941
{
4042
_fileStorage = fileStorage;
4143
_fileNameResolver = fileNameResolver;
4244
_searchTermResolver = searchTermResolver;
45+
_errorMessageProvider = errorMessageProvider;
4346
_apiUrlBuilder = apiUrlBuilder;
4447
_viewer = viewer;
4548
_logger = logger;
@@ -67,7 +70,10 @@ public async Task<IActionResult> ListDir([FromBody] ListDirRequest request)
6770
{
6871
_logger.LogError(ex, "Failed to load file tree.");
6972

70-
return ErrorJsonResult(ex.Message);
73+
var ctx = new ErrorContext(ApiNames.API_METHOD_LIST_DIR, HttpContext);
74+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
75+
76+
return ErrorJsonResult(msg);
7177
}
7278
}
7379

@@ -92,7 +98,10 @@ public async Task<IActionResult> UploadFile()
9298
{
9399
_logger.LogError(ex, "Failed to upload document.");
94100

95-
return ErrorJsonResult(ex.Message);
101+
var ctx = new ErrorContext(ApiNames.API_METHOD_UPLOAD_FILE, HttpContext);
102+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
103+
104+
return ErrorJsonResult(msg);
96105
}
97106
}
98107

@@ -137,7 +146,10 @@ public async Task<IActionResult> ViewData([FromBody] ViewDataRequest request)
137146

138147
_logger.LogError(ex, "Failed to read document description.");
139148

140-
return ErrorJsonResult(ex.Message);
149+
var ctx = new ErrorContext(ApiNames.API_METHOD_VIEW_DATA, HttpContext);
150+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
151+
152+
return ErrorJsonResult(msg);
141153
}
142154
}
143155

@@ -166,7 +178,10 @@ public async Task<IActionResult> CreatePages([FromBody] CreatePagesRequest reque
166178

167179
_logger.LogError(ex, "Failed to retrieve document pages.");
168180

169-
return ErrorJsonResult(ex.Message);
181+
var ctx = new ErrorContext(ApiNames.API_METHOD_CREATE_PAGES, HttpContext);
182+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
183+
184+
return ErrorJsonResult(msg);
170185
}
171186
}
172187

@@ -202,7 +217,10 @@ public async Task<IActionResult> CreatePdf([FromBody] CreatePdfRequest request)
202217

203218
_logger.LogError(ex, "Failed to create PDF file.");
204219

205-
return ErrorJsonResult(ex.Message);
220+
var ctx = new ErrorContext(ApiNames.API_METHOD_CREATE_PDF, HttpContext);
221+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
222+
223+
return ErrorJsonResult(msg);
206224
}
207225
}
208226

@@ -220,7 +238,10 @@ public async Task<IActionResult> GetPage([FromQuery] GetPageRequest request)
220238
{
221239
_logger.LogError(ex, "Failed to retrieve document page.");
222240

223-
return ErrorJsonResult(ex.Message);
241+
var ctx = new ErrorContext(ApiNames.API_METHOD_GET_PAGE, HttpContext);
242+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
243+
244+
return ErrorJsonResult(msg);
224245
}
225246
}
226247

@@ -238,7 +259,10 @@ public async Task<IActionResult> GetThumb([FromQuery] GetThumbRequest request)
238259
{
239260
_logger.LogError(ex, "Failed to retrieve document thumb.");
240261

241-
return ErrorJsonResult(ex.Message);
262+
var ctx = new ErrorContext(ApiNames.API_METHOD_GET_THUMB, HttpContext);
263+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
264+
265+
return ErrorJsonResult(msg);
242266
}
243267
}
244268

@@ -262,7 +286,10 @@ public async Task<IActionResult> GetPdf([FromQuery] GetPdfRequest request)
262286
{
263287
_logger.LogError(ex, "Failed to retrieve PDF file.");
264288

265-
return ErrorJsonResult(ex.Message);
289+
var ctx = new ErrorContext(ApiNames.API_METHOD_GET_PDF, HttpContext);
290+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
291+
292+
return ErrorJsonResult(msg);
266293
}
267294
}
268295

@@ -289,7 +316,10 @@ public async Task<IActionResult> GetResource([FromQuery] GetResourceRequest requ
289316
{
290317
_logger.LogError(ex, "Failed to load document page resource.");
291318

292-
return ErrorJsonResult(ex.Message);
319+
var ctx = new ErrorContext(ApiNames.API_METHOD_GET_RESOURCE, HttpContext);
320+
var msg = _errorMessageProvider.GetErrorMessage(ex, ctx);
321+
322+
return ErrorJsonResult(msg);
293323
}
294324
}
295325

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using Microsoft.AspNetCore.Http;
3+
4+
namespace GroupDocs.Viewer.UI.Api
5+
{
6+
/// <summary>
7+
/// Represents contextual information for an error message,
8+
/// including the API method where the exception occurred and the associated HTTP context.
9+
/// </summary>
10+
public record ErrorContext
11+
{
12+
/// <summary>
13+
/// The name of the API method where the exception occurred.
14+
/// </summary>
15+
public string ApiMethod { get; init; }
16+
17+
/// <summary>
18+
/// The HTTP context associated with the request.
19+
/// </summary>
20+
public HttpContext HttpContext { get; init; }
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="ErrorMessageContext"/> record.
24+
/// </summary>
25+
/// <param name="apiMethod">The API method name.</param>
26+
/// <param name="httpContext">The associated HTTP context.</param>
27+
/// <exception cref="ArgumentNullException">Thrown if any parameter is null.</exception>
28+
public ErrorContext(string apiMethod, HttpContext httpContext)
29+
{
30+
ApiMethod = apiMethod ?? throw new ArgumentNullException(nameof(apiMethod));
31+
HttpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
32+
}
33+
}
34+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
namespace GroupDocs.Viewer.UI.Api
3+
{
4+
/// <summary>
5+
/// Defines a contract for providing user-friendly error messages based on exceptions.
6+
/// Implementations can customize how error messages are generated for different exception types.
7+
/// </summary>
8+
public interface IErrorMessageProvider
9+
{
10+
/// <summary>
11+
/// Retrieves an error message based on the given exception.
12+
/// The returned message is intended to be displayed on the UI.
13+
/// </summary>
14+
/// <param name="exception">The exception to process.</param>
15+
/// <param name="context">The exception message context.</param>
16+
/// <returns>A user-friendly error message.</returns>
17+
string GetErrorMessage(Exception exception, ErrorContext context);
18+
}
19+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace GroupDocs.Viewer.UI.Api
4+
{
5+
/// Provides a default implementation for retrieving error messages from exceptions.
6+
/// The returned message is displayed on the UI.
7+
/// </summary>
8+
public class ExceptionMessageProvider : IErrorMessageProvider
9+
{
10+
/// <inheritdoc />
11+
public string GetErrorMessage(Exception exception, ErrorContext context) => exception.Message;
12+
}
13+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# UI for GroupDocs.Viewer for .NET (API)
2+
3+
`GroupDocs.Viewer.UI.Api` contains base types for implementing an API for `GroupDocs.Viewer.UI`.
4+
5+
There are two API implementations provided within this package:
6+
7+
* `GroupDocs.Viewer.UI.SelfHost.Api` - A self-hosted service that uses the
8+
[GroupDocs.Viewer](https://www.nuget.org/packages/groupdocs.viewer) package.
9+
* `GroupDocs.Viewer.UI.Cloud.Api` - Uses the cloud API provided by GroupDocs.
10+
11+
This readme includes information and usage examples for the features provided by this module.
12+
13+
## Features
14+
15+
This section lists the features provided by the module.
16+
17+
### Error Handling
18+
19+
Types that enable you to display custom error messages can be found in the [ErrorHandling](./ErrorHandling) folder.
20+
The key type here is the [ErrorMessageProvider.cs](./ErrorMessageProvider.cs) interface, which defines a contract for providing user-friendly error messages based on exceptions.
21+
22+
The following code demonstrates how to implement a custom error message provider:
23+
24+
```cs
25+
using GroupDocs.Viewer.UI.Api;
26+
27+
//...
28+
29+
public class MyErrorMessageProvider : IErrorMessageProvider
30+
{
31+
public string GetErrorMessage(Exception exception, ErrorContext context)
32+
{
33+
return "This is my custom error message...";
34+
}
35+
}
36+
```
37+
38+
Once the custom error message provider is implemented, it can be registered during the application composition stage.
39+
40+
The following code snippet shows how to register a custom service as a singleton:
41+
42+
```cs
43+
using GroupDocs.Viewer.UI.Api;
44+
45+
var builder = WebApplication.CreateBuilder(args);
46+
47+
builder.Services.AddSingleton<IErrorMessageProvider, MyErrorMessageProvider>();
48+
```
49+
50+
**NOTE:** The service should be registered before you register the self-hosted or cloud API for it to take effect.
51+
52+
By default, [ExceptionMessageProvider.cs](./ErrorHandling/ExceptionMessageProvider.cs) is registered.
53+
This class provides a default implementation that returns the exception error message.
54+
55+
Once a custom error message provider is registered, a popup with the custom error message will be displayed in case of an error.
56+
57+
![GroupDocs.Viewer.UI - Custom error message](https://raw.githubusercontent.com/groupdocs-viewer/groupdocs-viewer.github.io/master/resources/image/ui/custom-error-message.png)

src/GroupDocs.Viewer.UI.Cloud.Api/Extensions/MvcBuilderExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public static GroupDocsViewerUIApiBuilder AddGroupDocsViewerCloudApi(this IMvcBu
7171
builder.Services.AddTransient<IFileCache, NoopFileCache>();
7272
builder.Services.TryAddSingleton<IFileNameResolver, FilePathFileNameResolver>();
7373
builder.Services.TryAddSingleton<ISearchTermResolver, SearchTermResolver>();
74+
builder.Services.TryAddSingleton<IErrorMessageProvider, ExceptionMessageProvider>();
7475
builder.Services.TryAddSingleton<IPageFormatter, NoopPageFormatter>();
7576
builder.Services.TryAddSingleton<IUIConfigProvider, UIConfigProvider>();
7677

src/GroupDocs.Viewer.UI.SelfHost.Api.Shared/Extensions/MvcBuilderExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static GroupDocsViewerUIApiBuilder AddGroupDocsViewerSelfHostApi(this IMv
4949
builder.Services.TryAddSingleton<IFileTypeResolver, FileExtensionFileTypeResolver>();
5050
builder.Services.TryAddSingleton<IPageFormatter, NoopPageFormatter>();
5151
builder.Services.TryAddSingleton<ISearchTermResolver, SearchTermResolver>();
52+
builder.Services.TryAddSingleton<IErrorMessageProvider, ExceptionMessageProvider>();
5253
builder.Services.TryAddSingleton<IUIConfigProvider, UIConfigProvider>();
5354

5455
if (config.InternalCacheOptions.IsCacheEnabled)

0 commit comments

Comments
 (0)