Skip to content

Commit 168e45d

Browse files
Merge 8.0.3 branch into main (#67)
* Add support for setting the initial zoom level * Handle case when zoom level is not specified * Add support to show custom error message * Update path to the file in readme * Operate with URL.createObjectURL() temporary blob objects instead of links to pages in image mode * Optimize page loading by avoiding the loading of scrolled-past pages * Update dependencies * Update package versions to 8.0.3
1 parent 75c9e1c commit 168e45d

File tree

15 files changed

+268
-26
lines changed

15 files changed

+268
-26
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,31 @@ builder.Services
166166
});
167167
```
168168

169+
#### Set initial zoom level
170+
171+
By default, the zoom level is not specified and selected by the UI to fit the document if possible.
172+
The default value can be changed using `InitialZoom` property. Available zoom levels are:
173+
174+
* `ZoomLevel.FitWidth`
175+
* `ZoomLevel.FitHeight`
176+
* `ZoomLevel.Percent25`
177+
* `ZoomLevel.Percent50`
178+
* `ZoomLevel.Percent100`
179+
* `ZoomLevel.Percent200`
180+
* `ZoomLevel.Percent300`
181+
182+
183+
The following code shows how to set default zoom level to fit document by width.
184+
185+
```cs
186+
builder.Services
187+
.AddGroupDocsViewerUI(config =>
188+
{
189+
config.InitialZoom = ZoomLevel.FitWidth;
190+
});
191+
```
192+
193+
169194
### Disable context menu
170195

171196
To disable context menu or mouse right click, set `EnableContextMenu` to `false`. By default, feature is enabled.

build/dependencies.props

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</PropertyGroup>
1717

1818
<PropertyGroup Label="Package Versions">
19-
<GroupDocsViewer>25.1.1</GroupDocsViewer>
19+
<GroupDocsViewer>25.3.0</GroupDocsViewer>
2020

2121
<MicrosoftExtensionsHttp>8.0.1</MicrosoftExtensionsHttp>
2222
<MicrosoftExtensionsDependencyInjectionAbstractions>8.0.2</MicrosoftExtensionsDependencyInjectionAbstractions>
@@ -28,25 +28,25 @@
2828

2929
<SystemTextJson>8.0.5</SystemTextJson>
3030

31-
<AzureBlobs>12.23.0</AzureBlobs>
32-
<AwsSdkS3>3.7.410.8</AwsSdkS3>
31+
<AzureBlobs>12.24.0</AzureBlobs>
32+
<AwsSdkS3>3.7.416.3</AwsSdkS3>
3333

3434
<MicrosoftSourceLinkGithub>8.0.0</MicrosoftSourceLinkGithub>
3535
</PropertyGroup>
3636

3737
<PropertyGroup Label="GroupDocs.Viewer UI Package Versions">
38-
<GroupDocsViewerUI>8.0.2</GroupDocsViewerUI>
39-
<GroupDocsViewerUIApi>8.0.2</GroupDocsViewerUIApi>
40-
<GroupDocsViewerUIApiLocalCache>8.0.2</GroupDocsViewerUIApiLocalCache>
41-
<GroupDocsViewerUIApiInMemoryCache>8.0.2</GroupDocsViewerUIApiInMemoryCache>
42-
<GroupDocsViewerUIApiLocalStorage>8.0.2</GroupDocsViewerUIApiLocalStorage>
43-
<GroupDocsViewerUIApiCloudStorage>8.0.2</GroupDocsViewerUIApiCloudStorage>
44-
<GroupDocsViewerUIApiAzureStorage>8.0.2</GroupDocsViewerUIApiAzureStorage>
45-
<GroupDocsViewerUIApiAwsS3Storage>8.0.2</GroupDocsViewerUIApiAwsS3Storage>
46-
<GroupDocsViewerUICore>8.0.2</GroupDocsViewerUICore>
47-
<GroupDocsViewerUISelfHostApi>8.0.2</GroupDocsViewerUISelfHostApi>
48-
<GroupDocsViewerUISelfHostApiCrossPlatform>8.0.2</GroupDocsViewerUISelfHostApiCrossPlatform>
49-
<GroupDocsViewerUICloudApi>8.0.2</GroupDocsViewerUICloudApi>
38+
<GroupDocsViewerUI>8.0.3</GroupDocsViewerUI>
39+
<GroupDocsViewerUIApi>8.0.3</GroupDocsViewerUIApi>
40+
<GroupDocsViewerUIApiLocalCache>8.0.3</GroupDocsViewerUIApiLocalCache>
41+
<GroupDocsViewerUIApiInMemoryCache>8.0.3</GroupDocsViewerUIApiInMemoryCache>
42+
<GroupDocsViewerUIApiLocalStorage>8.0.3</GroupDocsViewerUIApiLocalStorage>
43+
<GroupDocsViewerUIApiCloudStorage>8.0.3</GroupDocsViewerUIApiCloudStorage>
44+
<GroupDocsViewerUIApiAzureStorage>8.0.3</GroupDocsViewerUIApiAzureStorage>
45+
<GroupDocsViewerUIApiAwsS3Storage>8.0.3</GroupDocsViewerUIApiAwsS3Storage>
46+
<GroupDocsViewerUICore>8.0.3</GroupDocsViewerUICore>
47+
<GroupDocsViewerUISelfHostApi>8.0.3</GroupDocsViewerUISelfHostApi>
48+
<GroupDocsViewerUISelfHostApiCrossPlatform>8.0.3</GroupDocsViewerUISelfHostApiCrossPlatform>
49+
<GroupDocsViewerUICloudApi>8.0.3</GroupDocsViewerUICloudApi>
5050
</PropertyGroup>
5151

5252
</Project>
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: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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](./ErrorHandling/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. By default, [ExceptionMessageProvider.cs](./ErrorHandling/ExceptionMessageProvider.cs) is registered.
51+
This class provides a default implementation that returns the exception error message.
52+
53+
Once a custom error message provider is registered, a popup with the custom error message will be displayed in case of an error.
54+
55+
![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.Core/Configuration/Config.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public class Config
2525
/// </summary>
2626
public int PreloadPages { get; set; } = 3;
2727

28+
/// <summary>
29+
// Initial zoom level. The default value is not specified; the UI automatically sets the zoom level.
30+
/// </summary>
31+
public ZoomLevel InitialZoom { get; set; }
32+
2833
/// <summary>
2934
/// Enable or disable right-click context menu
3035
/// </summary>

0 commit comments

Comments
 (0)