<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <title>ABP.IO Stories</title>
    <link>https://abp.io/community/articles</link>
    <description>A hub for ABP Framework, .NET, and software development. Access articles, tutorials, news, and contribute to the ABP community.</description>
    <lastBuildDate>Sun, 01 Nov 2026 21:00:30 Z</lastBuildDate>
    <generator>Community - ABP.IO</generator>
    <image>
      <url>https://abp.io/assets/favicon.ico/favicon-32x32.png</url>
      <title>ABP.IO Stories</title>
      <link>https://abp.io/community/articles</link>
    </image>
    <a10:link rel="self" type="application/rss+xml" title="self" href="https://abp.io/community/rss?member=jakeuj" />
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-suite-tutorial-customizing-entity-consts-server.entity.entityconsts.txt-k7g1t62q</guid>
      <link>https://abp.io/community/posts/abp-suite-tutorial-customizing-entity-consts-server.entity.entityconsts.txt-k7g1t62q</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <category>customization</category>
      <category>abp-suite</category>
      <category>custom-template</category>
      <category>crud-page-generator</category>
      <category>tutorial</category>
      <title>ABP Suite Tutorial: Customizing Entity Consts (Server.Entity.EntityConsts.txt)</title>
      <description>This article explains how to customize the `Server.Entity.EntityConsts.txt` template in ABP Suite, including how to modify auto-generated field length constants, add additional custom constants, and prevent your changes from being overwritten when regenerating CRUD pages. It provides practical examples, file structure explanations, and naming recommendations to help developers build a cleaner and more maintainable constant management strategy in ABP projects.
</description>
      <pubDate>Fri, 28 Nov 2025 03:37:04 Z</pubDate>
      <a10:updated>2026-04-19T00:41:38Z</a10:updated>
      <content:encoded><![CDATA[This article explains how to customize the `Server.Entity.EntityConsts.txt` template in ABP Suite, including how to modify auto-generated field length constants, add additional custom constants, and prevent your changes from being overwritten when regenerating CRUD pages. It provides practical examples, file structure explanations, and naming recommendations to help developers build a cleaner and more maintainable constant management strategy in ABP projects.
<br \><a href="https://jakeuj.com/abp-suite-entity-consts.html" rel="nofollow noopener noreferrer" title="Go to the Post">Go to the Post</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1ddab6-04c4-ca4b-2527-fb07acb8bb27" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1ddab6-04c4-ca4b-2527-fb07acb8bb27" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp-suiteefcorerepository-template-change-dbcontext-l77qc8tb</guid>
      <link>https://abp.io/community/posts/abp-suiteefcorerepository-template-change-dbcontext-l77qc8tb</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <category>EfCore</category>
      <category>entity-framework-core</category>
      <category>repository</category>
      <category>abp-suite</category>
      <category>multiple-contexts</category>
      <title>ABP Suite：EfCoreRepository Template change DbContext</title>
      <description>在 ABP Suite 專案中，若有多個 DbContext，預設的 Repository Template 可能會判斷錯誤，導致產生到錯誤的 DbContext。作者提供了一個簡單方法：修改 EfCoreRepository Template，強制指定使用正確的 DbContext，以確保穩定性與一致性。</description>
      <pubDate>Fri, 28 Nov 2025 03:25:41 Z</pubDate>
      <a10:updated>2026-04-18T01:20:27Z</a10:updated>
      <content:encoded><![CDATA[在 ABP Suite 專案中，若有多個 DbContext，預設的 Repository Template 可能會判斷錯誤，導致產生到錯誤的 DbContext。作者提供了一個簡單方法：修改 EfCoreRepository Template，強制指定使用正確的 DbContext，以確保穩定性與一致性。<br \><a href="https://jakeuj.com/abp-suite-efcorerepository-template-dbcontext.html" rel="nofollow noopener noreferrer" title="Go to the Post">Go to the Post</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/images/others/blank-cover-image-150_79.png" />
      <media:content url="https://abp.io/images/others/blank-cover-image-150_79.png" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/auto-update-openiddict-cret-by-azure-key-vault-kqkgixdy</guid>
      <link>https://abp.io/community/posts/auto-update-openiddict-cret-by-azure-key-vault-kqkgixdy</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <category>azure</category>
      <category>openiddict</category>
      <category>abp</category>
      <category>openiddict-module</category>
      <title>Auto Update OpenIddict Cret by Azure Key Vault</title>
      <description>A practical guide on implementing automated certificate rotation for OpenIddict using **Azure Key Vault**, **Managed Identity**, and **Auto-Renew policies**.  
It shows how to load all valid certificates at startup, always sign tokens with the newest version, and still validate tokens issued by older certificates.  
Includes sample code, Key Vault policy.json, and Azure CLI scripts. Ideal for ABP + OpenIddict projects running on Azure App Service.</description>
      <pubDate>Wed, 26 Nov 2025 03:42:01 Z</pubDate>
      <a10:updated>2026-04-24T12:20:39Z</a10:updated>
      <content:encoded><![CDATA[A practical guide on implementing automated certificate rotation for OpenIddict using **Azure Key Vault**, **Managed Identity**, and **Auto-Renew policies**.  
It shows how to load all valid certificates at startup, always sign tokens with the newest version, and still validate tokens issued by older certificates.  
Includes sample code, Key Vault policy.json, and Azure CLI scripts. Ideal for ABP + OpenIddict projects running on Azure App Service.<br \><a href="https://jakeuj.com/azure-key-vault-openiddict.html#azure-cli" rel="nofollow noopener noreferrer" title="Go to the Post">Go to the Post</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1dd06d-d601-a771-c825-e7edfdfe20c8" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1dd06d-d601-a771-c825-e7edfdfe20c8" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/file-management-7uvs38b3</guid>
      <link>https://abp.io/community/posts/file-management-7uvs38b3</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <title>File Management</title>
      <description>在一个名为 "Backup" 的目录中创建备份文件。如果目录不存在，则会先创建该目录。</description>
      <pubDate>Thu, 10 Apr 2025 07:27:14 Z</pubDate>
      <a10:updated>2026-11-01T10:53:21Z</a10:updated>
      <content:encoded><![CDATA[<h1>File Management</h1>
<p>Must have pro license to use this module.</p>
<h2>Install</h2>
<pre><code class="language-powershell">abp add-module Volo.FileManagement
</code></pre>
<h2>Configure</h2>
<pre><code class="language-c#">private void ConfigureBlobStoring(IConfiguration configuration)
{
    Configure&lt;AbpBlobStoringOptions&gt;(options =&gt;
    {
        options.Containers.Configure&lt;FileManagementContainer&gt;(c =&gt;
        {
            c.UseFileSystem(fileSystem =&gt;
            {
                fileSystem.BasePath = configuration[&quot;Path&quot;];
            }); // You can use Database or Azure providers also.
        });
    });
}
</code></pre>
<h2>Usage</h2>
<pre><code class="language-c#">private readonly IRepository&lt;DirectoryDescriptor&gt; _directoryDescriptorRepository;
private readonly FileManager _fileManager;

public TestFileManagementAppService(IRepository&lt;DirectoryDescriptor&gt; directoryDescriptorRepository,
    FileManager fileManager)
{
    _directoryDescriptorRepository = directoryDescriptorRepository;
    _fileManager = fileManager;
}

public async Task&lt;Guid?&gt; CreateBackupAsync(IRemoteStreamContent Content)
{
    var backup = await _directoryDescriptorRepository.FirstOrDefaultAsync(x =&gt;
        x.Name == &quot;Backup&quot; &amp;&amp; x.ParentId == null &amp;&amp; x.TenantId == null);
    if (backup == null)
    {
        backup = await _directoryDescriptorRepository.InsertAsync(
            new DirectoryDescriptor(GuidGenerator.Create(), &quot;Backup&quot;),
            true);
    }

    var f = await _fileManager.CreateAsync(Content.FileName, Content.ContentType, Content, backup.Id, null, true);
    return f.DirectoryId;
}
</code></pre>
<h3>代码解释</h3>
<p>该代码定义了一个名为 <code>TestFileManagementAppService</code> 的类，它继承自 <code>NbEdiAppService</code>，并提供了一个方法用于创建备份文件夹并将文件存储到其中。以下是代码的详细解释：</p>
<h3>构造函数</h3>
<pre><code class="language-c#">public TestFileManagementAppService(IRepository&lt;DirectoryDescriptor&gt; directoryDescriptorRepository,
    FileManager fileManager)
</code></pre>
<p>构造函数接收两个依赖项：<code>IRepository&lt;DirectoryDescriptor&gt;</code> 和 <code>FileManager</code>。</p>
<ul>
<li><code>IRepository&lt;DirectoryDescriptor&gt;</code> 用于操作 <code>DirectoryDescriptor</code> 实体（目录描述符），例如查询或插入目录。</li>
<li><code>FileManager</code> 用于管理文件的创建和存储。</li>
</ul>
<p>这些依赖项通过依赖注入传递给类，并存储在私有字段 <code>_directoryDescriptorRepository</code> 和 <code>_fileManager</code> 中。</p>
<hr />
<h3><code>CreateBackupAsync</code> 方法</h3>
<pre><code class="language-c#">public async Task&lt;Guid?&gt; CreateBackupAsync(IRemoteStreamContent Content)
</code></pre>
<p>该方法的目的是在一个名为 &quot;Backup&quot; 的目录中创建备份文件。如果目录不存在，则会先创建该目录。</p>
<ol>
<li><p><strong>查找或创建备份目录</strong>：</p>
<pre><code class="language-c#">var backup = await _directoryDescriptorRepository.FirstOrDefaultAsync(x =&gt;
    x.Name == &quot;Backup&quot; &amp;&amp; x.ParentId == null &amp;&amp; x.TenantId == null);
</code></pre>
<p>这里通过 <code>FirstOrDefaultAsync</code> 方法查询名为 &quot;Backup&quot; 的根目录（<code>ParentId == null</code> 且 <code>TenantId == null</code>）。如果目录不存在：</p>
<pre><code class="language-c#">backup = await _directoryDescriptorRepository.InsertAsync(
    new DirectoryDescriptor(GuidGenerator.Create(), &quot;Backup&quot;),
    true);
</code></pre>
<p>使用 <code>InsertAsync</code> 方法创建一个新的 <code>DirectoryDescriptor</code> 实体，并将其插入到存储库中。</p>
</li>
<li><p><strong>创建文件</strong>：</p>
<pre><code class="language-c#">var f = await _fileManager.CreateAsync(Content.FileName, Content.ContentType, Content, backup.Id, null, true);
</code></pre>
<p>使用 <code>FileManager</code> 的 <code>CreateAsync</code> 方法将文件存储到备份目录中。方法参数包括文件名、内容类型、文件内容、目标目录 ID 等。</p>
</li>
<li><p><strong>返回目录 ID</strong>：</p>
<pre><code class="language-c#">return f.DirectoryId;
</code></pre>
<p>方法返回文件所属目录的 ID（即备份目录的 ID）。</p>
</li>
</ol>
<hr />
<h3>总结</h3>
<p>该类的主要功能是确保存在一个名为 &quot;Backup&quot; 的目录，并将传入的文件存储到该目录中。通过依赖注入的方式，代码实现了对目录和文件的解耦管理，便于扩展和测试。</p>
<h2>Ref</h2>
<p><a href="https://abp.io/docs/latest/modules/file-management">file-management</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1930c5-5faf-b2d4-526e-b56e04374e0d" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1930c5-5faf-b2d4-526e-b56e04374e0d" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/file-system-get-directory-files-hesdyg19</guid>
      <link>https://abp.io/community/posts/file-system-get-directory-files-hesdyg19</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <title>File System Get Directory Files</title>
      <description>Retrieve all file names in a folder using the GetFileNameList extension method, and then iterate through the list to access the file contents.</description>
      <pubDate>Thu, 10 Apr 2025 07:24:51 Z</pubDate>
      <a10:updated>2026-11-01T10:48:17Z</a10:updated>
      <content:encoded><![CDATA[<h1>File System</h1>
<h2>Install</h2>
<pre><code class="language-powershell">abp add-package Volo.Abp.BlobStoring.FileSystem
</code></pre>
<h2>Configure</h2>
<pre><code class="language-c#">private void ConfigureBlobStoring(IConfiguration configuration)
{
    Configure&lt;AbpBlobStoringOptions&gt;(options =&gt;
    {
        options.Containers.ConfigureDefault(container =&gt;
        {
            container.UseFileSystem(fileSystem =&gt;
            {
                fileSystem.BasePath = configuration[&quot;Path&quot;];
            });
        });
        // temp is a container name
        options.Containers.Configure(&quot;temp&quot;, container =&gt;
            {
                container.UseFileSystem(fileSystem =&gt;
                {
                    fileSystem.BasePath = configuration[&quot;BlobOptions:BlobPath&quot;];
                });
            });
    });
}
</code></pre>
<h2>Usage</h2>
<pre><code class="language-c#">private readonly IBlobContainer _blobContainer;
private readonly IConfiguration _configuration;

public TestFileSystemAppService(IBlobContainerFactory blobContainerFactory, IConfiguration configuration)
{
    _configuration = configuration;
    _blobContainer = blobContainerFactory.Create(&quot;temp&quot;);
}

public async Task SaveBytesAsync(byte[] bytes)
{
    await _blobContainer.SaveAsync(&quot;my-blob-1&quot;, bytes, true);
}

public async Task&lt;byte[]?&gt; GetBytesAsync()
{
    return await _blobContainer.GetAllBytesOrNullAsync(&quot;my-blob-1&quot;);
}

public async Task SaveStreamAsync(IRemoteStreamContent Content)
{
    await _blobContainer.SaveAsync(Content.FileName ?? &quot;my-blob-2&quot;, Content.GetStream(), true);
}

public async Task&lt;IRemoteStreamContent?&gt; GetStreamAsync(string? fileName = &quot;my-blob-2&quot;)
{
    if (string.IsNullOrEmpty(fileName))
    {
        throw new ArgumentNullException(nameof(fileName));
    }

    var s = await _blobContainer.GetOrNullAsync(fileName);
    if (s == null)
    {
        throw new NotFoundException();
    }

    return new RemoteStreamContent(s, fileName,
        &quot;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet&quot;);
}

public async Task SaveDirectoryAsync(IRemoteStreamContent Content)
{
    await _blobContainer.SaveAsync(Path.Combine(&quot;DirName&quot;, &quot;SubDir&quot;, Content.FileName), Content.GetStream(), true);
}

public async Task GetEdisync(string name)
{
    var s = await _blobContainer.GetOrNullAsync(Path.Combine(&quot;DirName&quot;, &quot;SubDir&quot;,name));
    if (s == null)
    {
        throw new NotFoundException();
    }
}

public async Task&lt;IEnumerable&lt;string&gt;&gt; GetDirectoryAsync()
{
    return _blobContainer.GetFileNameList(Path.Combine(_configuration[&quot;Path&quot;], &quot;host&quot;, &quot;DirName&quot;, &quot;SubDir&quot;));
}
</code></pre>
<h2>GetDirectoryFiles</h2>
<p>Retrieve all file names in a folder using the <code>GetFileNameList</code> extension method, and then iterate through the list to access the file contents.</p>
<h3>extension</h3>
<p>Create a extension method to get file name list from directory.</p>
<p><code>public static class NbEdiExtensions</code></p>
<pre><code class="language-c#">public static List&lt;string&gt; GetFileNameList(
    this IBlobContainer blobContainer,
    string blobPath,
    string? subPath = null)
{
    if (!string.IsNullOrWhiteSpace(subPath))
    {
        blobPath = Path.Combine(blobPath, subPath);
    }

    if (!Directory.Exists(blobPath))
    {
        return new List&lt;string&gt;();
    }

    var di = new DirectoryInfo(blobPath);

    return di.GetFiles().Select(x =&gt; x.Name).ToList();
}
</code></pre>
<p>P.S. You can also add checks for TenantId and UserId to retrieve file lists for different tenants and users.</p>
<p>该方法 <code>GetFileNameList</code> 是一个扩展方法，用于从指定的本地文件系统路径中获取文件名列表。它接受三个参数：<code>IBlobContainer</code> 接口实例（尽管未在方法中直接使用）、<code>blobPath</code>（文件夹路径）以及可选的子路径 <code>subPath</code>。</p>
<h3>参数处理</h3>
<p>首先，方法检查 <code>subPath</code> 是否为空或仅包含空白字符：</p>
<pre><code class="language-c#">if (!string.IsNullOrWhiteSpace(subPath))
{
    blobPath = Path.Combine(blobPath, subPath);
}
</code></pre>
<p>如果 <code>subPath</code> 有效，则将其与 <code>blobPath</code> 合并，生成完整的路径。</p>
<h3>路径验证</h3>
<p>接下来，方法验证合并后的路径是否存在：</p>
<pre><code class="language-c#">if (!Directory.Exists(blobPath))
{
    return new List&lt;string&gt;();
}
</code></pre>
<p>如果路径不存在，则返回一个空的字符串列表，表示没有可用的文件。</p>
<h3>获取文件名列表</h3>
<p>如果路径存在，方法会创建一个 <code>DirectoryInfo</code> 实例来表示该目录：</p>
<pre><code class="language-c#">var di = new DirectoryInfo(blobPath);
</code></pre>
<p>然后通过调用 <code>GetFiles</code> 方法获取目录中的所有文件，并使用 LINQ 将每个文件的名称提取为字符串列表：</p>
<pre><code class="language-c#">return di.GetFiles().Select(x =&gt; x.Name).ToList();
</code></pre>
<h3>总结</h3>
<p>该方法的主要功能是从指定的本地目录中获取文件名列表。它通过路径合并和验证确保了输入路径的有效性，并使用 <code>DirectoryInfo</code> 和 LINQ 提供了简洁的文件名提取逻辑。如果路径无效或不存在，则返回空列表。</p>
<h2>Ref</h2>
<p><a href="https://abp.io/docs/latest/framework/infrastructure/blob-storing/file-system">file-system</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a1930c3-2e3a-8114-2d57-edc9c97f18cc" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a1930c3-2e3a-8114-2d57-edc9c97f18cc" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/abp.io-webying-yong-cheng-shi-kuang-jia-sendgrid-zheng-he-w9dvss6v</guid>
      <link>https://abp.io/community/posts/abp.io-webying-yong-cheng-shi-kuang-jia-sendgrid-zheng-he-w9dvss6v</link>
      <a10:author>
        <a10:name>jakeuj</a10:name>
        <a10:uri>https://abp.io/community/members/jakeuj</a10:uri>
      </a10:author>
      <title>ABP.IO WEB應用程式框架 SendGrid 整合</title>
      <description>使用 SendGrid 實作 IEmailSender 替換服務</description>
      <pubDate>Fri, 28 Jul 2023 07:14:10 Z</pubDate>
      <a10:updated>2026-03-11T02:58:29Z</a10:updated>
      <content:encoded><![CDATA[使用 SendGrid 實作 IEmailSender 替換服務<br \><a href="https://www.dotblogs.com.tw/jakeuj/2023/02/13/ABP-SendGrid-IEmailSender-Attachments" rel="nofollow noopener noreferrer" title="Go to the Post">Go to the Post</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/3a0cad85-df28-8bcd-9e07-8733a760f561" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/3a0cad85-df28-8bcd-9e07-8733a760f561" medium="image" />
    </item>
  </channel>
</rss>