Skip to content

Commit 10fc302

Browse files
committed
Fixed possible null reference issues
1 parent 92ee4ef commit 10fc302

File tree

5 files changed

+93
-59
lines changed

5 files changed

+93
-59
lines changed

Src/Axuno.VirtualFileSystem/Axuno.VirtualFileSystem.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
<SignAssembly>true</SignAssembly>
77
<!-- sn -k Axuno.VirtualFileSystem.snk -->
88
<AssemblyOriginatorKeyFile>Axuno.VirtualFileSystem.snk</AssemblyOriginatorKeyFile>
9-
<Version>1.0.0</Version>
9+
<Version>1.0.1</Version>
1010
<Authors>axuno gGmbH</Authors>
1111
<Company>axuno gGmbH</Company>
1212
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
1313
<PackageIcon>VirtualFileSystem.png</PackageIcon>
1414
<RepositoryUrl>https://github.com/axuno/Axuno.VirtualFileSystem</RepositoryUrl>
1515
<RepositoryType>Git</RepositoryType>
1616
<PackageTags>virtual file system netstandard c#</PackageTags>
17-
<PackageReleaseNotes>Added unit tests
18-
Bumped to v1.0.0</PackageReleaseNotes>
17+
<PackageReleaseNotes>Fixed possible null reference issues
18+
Bumped to v1.0.1</PackageReleaseNotes>
1919
<Copyright>© 2013 - 2021 Volosoft. Open source license with LGPLv3.0</Copyright>
2020
<Description>The Virtual File System makes it possible to manage files that do not exist on a physical file system (e.g. disk).
2121

@@ -24,7 +24,7 @@ Bumped to v1.0.0</PackageReleaseNotes>
2424
* Virtual files can be used just like static files in an application.
2525
* JavaScript, CSS, image files and all other file types can be embedded into assemblies and used just like the static files.
2626

27-
The library is a modified version of Volo.Abp.VirtualFileSystem 4.1</Description>
27+
The library is a modified version of Volo.Abp.VirtualFileSystem 4.2</Description>
2828
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
2929
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
3030
</PropertyGroup>

Src/Axuno.VirtualFileSystem/DictionaryExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Axuno.VirtualFileSystem
1010
public static class DictionaryExtensions
1111
{
1212
/// <summary>
13-
/// This method is used to try to get a value in a dictionary if it does exists.
13+
/// This method is used to try to get a value in a dictionary if it exists.
1414
/// </summary>
1515
/// <typeparam name="T">Type of the value</typeparam>
1616
/// <param name="dictionary">The collection object</param>
@@ -19,7 +19,7 @@ public static class DictionaryExtensions
1919
/// <returns>True if key does exists in the dictionary</returns>
2020
internal static bool TryGetValue<T>(this IDictionary<string, object> dictionary, string key, out T value) where T : notnull
2121
{
22-
if (dictionary.TryGetValue(key, out object valueObj) && valueObj is T obj)
22+
if (dictionary.TryGetValue(key, out var valueObj) && valueObj is T obj)
2323
{
2424
value = obj;
2525
return true;
@@ -37,9 +37,9 @@ internal static bool TryGetValue<T>(this IDictionary<string, object> dictionary,
3737
/// <typeparam name="TKey">Type of the key</typeparam>
3838
/// <typeparam name="TValue">Type of the value</typeparam>
3939
/// <returns>Value if found, default if can not found.</returns>
40-
public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TValue : notnull
40+
public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) where TValue : notnull where TKey : notnull
4141
{
42-
return dictionary.TryGetValue(key, out var obj) ? obj : default!;
42+
return (dictionary.TryGetValue(key, out var obj) ? obj : default) ?? throw new NullReferenceException($"A {typeof(TValue)} has null a default");
4343
}
4444

4545
/// <summary>
@@ -76,7 +76,7 @@ public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, T
7676
/// <typeparam name="TKey">Type of the key</typeparam>
7777
/// <typeparam name="TValue">Type of the value</typeparam>
7878
/// <returns>Value if found, default if can not found.</returns>
79-
public static TValue GetOrDefault<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary, TKey key) where TValue : notnull
79+
public static TValue GetOrDefault<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dictionary, TKey key) where TValue : notnull where TKey : notnull
8080
{
8181
return dictionary.TryGetValue(key, out var obj) ? obj : default!;
8282
}

Src/Axuno.VirtualFileSystem/DynamicFileProvider.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Microsoft.Extensions.FileProviders;
77
using Microsoft.Extensions.Primitives;
88

9-
109
namespace Axuno.VirtualFileSystem
1110
{
1211
/// <summary>
@@ -19,18 +18,35 @@ namespace Axuno.VirtualFileSystem
1918
/// </remarks>
2019
public class DynamicFileProvider : DictionaryBasedFileProvider, IDynamicFileProvider
2120
{
21+
/// <summary>
22+
/// Gets the <see cref="IDictionary{TKey,TValue}"/> for dynamic files.
23+
/// </summary>
24+
/// <remarks>This property can be overridden in a derived class.</remarks>
2225
protected override IDictionary<string, IFileInfo> Files => DynamicFiles;
2326

27+
/// <summary>
28+
/// Gets dynamic files as a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
29+
/// </summary>
2430
protected ConcurrentDictionary<string, IFileInfo> DynamicFiles { get; }
2531

32+
/// <summary>
33+
/// Gets the <see cref="ConcurrentDictionary{TKey,TValue}"/> for <see cref="ChangeTokenInfo"/>s.
34+
/// </summary>
2635
protected ConcurrentDictionary<string, ChangeTokenInfo> FilePathTokenLookup { get; }
2736

37+
/// <summary>
38+
/// CTOR.
39+
/// </summary>
2840
public DynamicFileProvider()
2941
{
3042
FilePathTokenLookup = new ConcurrentDictionary<string, ChangeTokenInfo>(StringComparer.OrdinalIgnoreCase);;
3143
DynamicFiles = new ConcurrentDictionary<string, IFileInfo>();
3244
}
3345

46+
/// <summary>
47+
/// Updates the existing <see cref="IFileInfo"/> or inserts a new one.
48+
/// </summary>
49+
/// <param name="fileInfo"></param>
3450
public void AddOrUpdate(IFileInfo fileInfo)
3551
{
3652
var filePath = fileInfo.GetVirtualOrPhysicalPath();
@@ -39,6 +55,11 @@ public void AddOrUpdate(IFileInfo fileInfo)
3955
ReportChange(filePath);
4056
}
4157

58+
/// <summary>
59+
/// Deletes a dynamic file.
60+
/// </summary>
61+
/// <param name="filePath"></param>
62+
/// <returns><see langword="true"/>, if the dynamic file was deleted.</returns>
4263
public bool Delete(string filePath)
4364
{
4465
if (!DynamicFiles.TryRemove(filePath, out _))
@@ -50,6 +71,11 @@ public bool Delete(string filePath)
5071
return true;
5172
}
5273

74+
/// <summary>
75+
/// Gets the <see cref="IChangeToken"/> for the given filter.
76+
/// </summary>
77+
/// <param name="filter"></param>
78+
/// <returns>The <see cref="IChangeToken"/> for the given filter.</returns>
5379
public override IChangeToken Watch(string filter)
5480
{
5581
return GetOrAddChangeToken(filter);
@@ -76,8 +102,16 @@ private void ReportChange(string filePath)
76102
}
77103
}
78104

105+
/// <summary>
106+
/// The <see cref="ChangeTokenInfo"/> structure.
107+
/// </summary>
79108
protected struct ChangeTokenInfo
80109
{
110+
/// <summary>
111+
/// CTOR.
112+
/// </summary>
113+
/// <param name="tokenSource"></param>
114+
/// <param name="changeToken"></param>
81115
public ChangeTokenInfo(
82116
CancellationTokenSource tokenSource,
83117
CancellationChangeToken changeToken)
@@ -86,8 +120,14 @@ public ChangeTokenInfo(
86120
ChangeToken = changeToken;
87121
}
88122

123+
/// <summary>
124+
/// Gets the <see cref="CancellationTokenSource"/>.
125+
/// </summary>
89126
public CancellationTokenSource TokenSource { get; }
90127

128+
/// <summary>
129+
/// Gets the <see cref="ChangeToken"/>.
130+
/// </summary>
91131
public CancellationChangeToken ChangeToken { get; }
92132
}
93133
}

Src/Axuno.VirtualFileSystem/Embedded/EmbeddedResourceFileInfo.cs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,29 @@ namespace Axuno.VirtualFileSystem.Embedded
1010
/// </summary>
1111
public class EmbeddedResourceFileInfo : IFileInfo
1212
{
13+
/// <summary>
14+
/// CTOR.
15+
/// </summary>
16+
/// <param name="assembly"></param>
17+
/// <param name="resourcePath"></param>
18+
/// <param name="virtualPath"></param>
19+
/// <param name="name"></param>
20+
/// <param name="lastModified"></param>
21+
public EmbeddedResourceFileInfo(
22+
Assembly assembly,
23+
string resourcePath,
24+
string virtualPath,
25+
string name,
26+
DateTimeOffset lastModified)
27+
{
28+
_assembly = assembly;
29+
_resourcePath = resourcePath;
30+
31+
VirtualPath = virtualPath;
32+
Name = name;
33+
LastModified = lastModified;
34+
}
35+
1336
public bool Exists => true;
1437

1538
public long Length
@@ -18,13 +41,11 @@ public long Length
1841
{
1942
if (!_length.HasValue)
2043
{
21-
using (var stream = _assembly.GetManifestResourceStream(_resourcePath))
22-
{
23-
_length = stream.Length;
24-
}
44+
using var stream = _assembly.GetManifestResourceStream(_resourcePath);
45+
_length = stream?.Length;
2546
}
2647

27-
return _length.Value;
48+
return 0;
2849
}
2950
}
3051
private long? _length;
@@ -36,7 +57,7 @@ public long Length
3657
public string Name { get; }
3758

3859
/// <summary>
39-
/// The time, in UTC.
60+
/// Gets the <see cref="DateTimeOffset"/>.
4061
/// </summary>
4162
public DateTimeOffset LastModified { get; }
4263

@@ -45,21 +66,6 @@ public long Length
4566
private readonly Assembly _assembly;
4667
private readonly string _resourcePath;
4768

48-
public EmbeddedResourceFileInfo(
49-
Assembly assembly,
50-
string resourcePath,
51-
string virtualPath,
52-
string name,
53-
DateTimeOffset lastModified)
54-
{
55-
_assembly = assembly;
56-
_resourcePath = resourcePath;
57-
58-
VirtualPath = virtualPath;
59-
Name = name;
60-
LastModified = lastModified;
61-
}
62-
6369
/// <inheritdoc />
6470
public Stream? CreateReadStream()
6571
{

Src/Axuno.VirtualFileSystem/StringExtensions.cs

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ public static string NormalizeLineEndings(this string str)
8585
/// <summary>
8686
/// Gets index of nth occurrence of a char in a string.
8787
/// </summary>
88-
/// <param name="str">source string to be searched</param>
89-
/// <param name="c">Char to search in <see cref="str"/></param>
88+
/// <param name="str"></param>
89+
/// <param name="c"></param>
9090
/// <param name="n">Count of the occurrence</param>
9191
public static int NthIndexOf(this string str, char c, int n)
9292
{
@@ -191,7 +191,7 @@ public static string ReplaceFirst(this string str, string search, string replace
191191
return str;
192192
}
193193

194-
return str.Substring(0, pos) + replace + str.Substring(pos + search.Length);
194+
return str.Substring(0, pos) + replace + str[(pos + search.Length)..];
195195
}
196196

197197
/// <summary>
@@ -261,7 +261,7 @@ public static string ToCamelCase(this string str, bool useCurrentCulture = false
261261
return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant();
262262
}
263263

264-
return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str.Substring(1);
264+
return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str[1..];
265265
}
266266

267267
/// <summary>
@@ -399,19 +399,17 @@ public static T ToEnum<T>(this string value, bool ignoreCase)
399399

400400
public static string ToMd5(this string str)
401401
{
402-
using (var md5 = MD5.Create())
403-
{
404-
var inputBytes = Encoding.UTF8.GetBytes(str);
405-
var hashBytes = md5.ComputeHash(inputBytes);
406-
407-
var sb = new StringBuilder();
408-
foreach (var hashByte in hashBytes)
409-
{
410-
sb.Append(hashByte.ToString("X2"));
411-
}
402+
using var md5 = MD5.Create();
403+
var inputBytes = Encoding.UTF8.GetBytes(str);
404+
var hashBytes = md5.ComputeHash(inputBytes);
412405

413-
return sb.ToString();
406+
var sb = new StringBuilder();
407+
foreach (var hashByte in hashBytes)
408+
{
409+
sb.Append(hashByte.ToString("X2"));
414410
}
411+
412+
return sb.ToString();
415413
}
416414

417415
/// <summary>
@@ -432,7 +430,7 @@ public static string ToPascalCase(this string str, bool useCurrentCulture = fals
432430
return useCurrentCulture ? str.ToUpper() : str.ToUpperInvariant();
433431
}
434432

435-
return (useCurrentCulture ? char.ToUpper(str[0]) : char.ToUpperInvariant(str[0])) + str.Substring(1);
433+
return (useCurrentCulture ? char.ToUpper(str[0]) : char.ToUpperInvariant(str[0])) + str[1..];
436434
}
437435

438436
/// <summary>
@@ -441,12 +439,7 @@ public static string ToPascalCase(this string str, bool useCurrentCulture = fals
441439
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
442440
public static string Truncate(this string str, int maxLength)
443441
{
444-
if (str.Length <= maxLength)
445-
{
446-
return str;
447-
}
448-
449-
return str.Left(maxLength);
442+
return str.Length <= maxLength ? str : str.Left(maxLength);
450443
}
451444

452445
/// <summary>
@@ -455,12 +448,7 @@ public static string Truncate(this string str, int maxLength)
455448
/// <exception cref="ArgumentNullException">Thrown if <paramref name="str"/> is null</exception>
456449
public static string TruncateFromBeginning(this string str, int maxLength)
457450
{
458-
if (str.Length <= maxLength)
459-
{
460-
return str;
461-
}
462-
463-
return str.Right(maxLength);
451+
return str.Length <= maxLength ? str : str.Right(maxLength);
464452
}
465453

466454
/// <summary>

0 commit comments

Comments
 (0)