URL 對外服務
插件最終需要(yào / yāo)以(yǐ) URL 路徑的(de)形式對外提供服務,可以(yǐ)是(shì)簡單的(de)靜态地(dì / de)址、Razor風格的(de)cshtml文件以(yǐ)及RESTful 風格的(de)Controller地(dì / de)址,根據實際需要(yào / yāo)可以(yǐ)靈活選擇。
我們以(yǐ) XYCMS 分享插件 (opens new window)爲(wéi / wèi)例說(shuō)明如何配置及使用URL 對外服務,下載分享插件源碼并使用 Visual Studio 打開項目,我們會發現如下結構:
紅框1 區域在(zài)項目根目錄的(de) wwwroot 文件夾下,通常爲(wéi / wèi) .css、.js、.png 或者 .html 等靜态資源文件,對外提供靜态資源訪問,資源文件的(de)最終訪問路徑與文件在(zài) wwwroot 文件夾下的(de)結構一(yī / yì /yí)緻,例如項目中 index.js 文件的(de)訪問地(dì / de)址爲(wéi / wèi) /assets/share/index.js。
紅框2 區域在(zài)項目根目錄的(de) Pages 文件夾下,用于(yú)支持 ASP.NET Core 中的(de) Razor Pages 功能,後綴通常爲(wéi / wèi) .cshtml。關于(yú) Razor Pages 的(de)更多信息可以(yǐ)參考 教程:在(zài) ASP.NET Core 中開始使用 Razor Pages (opens new window)。
紅框3 區域在(zài)項目根目錄的(de) Controllers 文件夾下,用于(yú)支持 ASP.NET Core 中的(de) Web API 功能。關于(yú) Web API 的(de)更多信息可以(yǐ)參考 使用 ASP.NET Core 創建 Web API (opens new window)。
靜态資源訪問
XYCMS 分享插件 (opens new window)通過 stl:share 實現前台頁面分享功能,最終在(zài)前台頁面生成如下所示的(de)小圖标,點擊圖标将實現分享:
由于(yú)前台頁面需要(yào / yāo)展示圖标并通過js實現分享功能,我們需要(yào / yāo)暴露靜态資源文件并提供給外部訪問,所以(yǐ)我們将資源文件統一(yī / yì /yí)放置到(dào) /wwwroot/assets/share 文件夾下。
最終插件資源文件的(de)訪問地(dì / de)址将以(yǐ) /assets/share/ 爲(wéi / wèi)URL地(dì / de)址前綴。之(zhī)所以(yǐ)以(yǐ)此路徑爲(wéi / wèi)前綴是(shì)爲(wéi / wèi)了(le/liǎo)避免與網站或其他(tā)插件的(de)資源文件地(dì / de)址沖突,實際上(shàng),我們可以(yǐ)将靜态資源文件放置在(zài) wwwroot 文件夾下的(de)任意路徑之(zhī)下。
Razor Pages 頁面
XYCMS 插件的(de) Razor Pages 頁面開發與 ASP.NET Core 中的(de) Razor Pages 頁面開發并無區别,XYCMS 系統啓動時(shí)将自動啓用各個(gè)插件的(de) Razor Pages 頁面支持。
關于(yú) Razor Pages 的(de)更多信息可以(yǐ)參考 教程:在(zài) ASP.NET Core 中開始使用 Razor Pages (opens new window)。
以(yǐ) XYCMS 分享插件 (opens new window)爲(wéi / wèi)例,我們需要(yào / yāo)在(zài)後台提供插件設置頁面,如下圖:
爲(wéi / wèi)了(le/liǎo)與 XYCMS 系統界面風格保持一(yī / yì /yí)緻,我們複用了(le/liǎo) XYCMS 的(de)基礎Layout布局:
@{ Layout = "_Layout"; }
以(yǐ)下是(shì)插件 Pages/ss-admin/share/Index.cshtml 文件的(de)源代碼,此頁面訪問路徑爲(wéi / wèi) /ss-admin/share/:
@page
@{ Layout = "_Layout"; }
<el-tabs type="border-card">
<el-tab-pane label="頁面分享設置">
<el-alert type="info">
頁面分享标簽:<strong><stl:share></stl:share></strong>
</el-alert>
<div style="height: 10px"></div>
<el-form size="small" ref="settingsForm" label-width="260px" status-icon :model="settingsForm">
<el-form-item label="默認頁面标題" prop="defaultTitle" :rules="{ required: true, message: '請輸入默認頁面标題' }">
<el-input v-model="settingsForm.defaultTitle" placeholder="請輸入默認頁面标題"></el-input>
<div class="tips">當分享插件未獲取到(dào)頁面标題時(shí)将使用默認頁面标題</div>
</el-form-item>
<el-form-item label="默認封面圖片" prop="defaultImageUrl" :rules="{ required: true, message: '請輸入圖片地(dì / de)址或點擊上(shàng)方按鈕上(shàng)傳' }">
<el-button-group>
<el-button size="mini" type="info" icon="el-icon-upload2" plain v-on:click="btnLayerClick({title: '上(shàng)傳圖片', name: 'formLayerImageUpload', attributeName: 'defaultImageUrl', no: 0})">
上(shàng)傳
</el-button>
<el-button size="mini" type="info" icon="el-icon-folder-opened" plain v-on:click="btnLayerClick({title: '選擇圖片素材', name: 'materialLayerImageSelect', attributeName: 'defaultImageUrl', no: 0, full: true})">
選擇
</el-button>
<el-button size="mini" type="info" icon="el-icon-view" plain :disabled="settingsForm.defaultImageUrl ? false : true" v-on:click="btnPreviewClick('defaultImageUrl', 0)">
預覽
</el-button>
</el-button-group>
<el-input
v-model="settingsForm.defaultImageUrl"
placeholder="請輸入圖片地(dì / de)址或點擊上(shàng)方按鈕上(shàng)傳">
</el-input>
<div class="tips">當分享插件未獲取到(dào)封面圖片時(shí)将使用默認封面圖片</div>
</el-form-item>
<el-form-item label="默認頁面介紹" prop="defaultDescription" :rules="{ required: true, message: '請輸入默認頁面介紹' }">
<el-input v-model="settingsForm.defaultDescription" type="textarea" :rows="5" placeholder="請輸入默認頁面介紹"></el-input>
<div class="tips">當分享插件未獲取到(dào)頁面介紹時(shí)将使用默認頁面介紹</div>
</el-form-item>
</el-form>
<el-divider></el-divider>
<div style="height: 10px"></div>
<el-row>
<el-col :span="24" align="center">
<el-button type="primary" v-on:click="btnSettingsSubmitClick" size="small">保 存</el-button>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="微信分享設置">
<el-alert v-if="mpResult && mpResult.success" type="success" title="微信公衆号設置保存成功!"></el-alert>
<el-alert v-else-if="mpResult && !mpResult.success" type="error" :title="mpResult.errorMessage" ></el-alert>
<div style="height: 10px"></div>
<el-form size="small" ref="wxShareForm" label-width="260px" status-icon :model="wxShareForm">
<el-form-item label="是(shì)否啓用微信分享">
<el-radio v-model="wxShareForm.isWxShare" :label="true">啓用</el-radio>
<el-radio v-model="wxShareForm.isWxShare" :label="false">不(bù)啓用</el-radio>
<div class="tips">啓用微信分享後,微信轉發或分享時(shí)将顯示完整的(de)标題、封面及介紹</div>
</el-form-item>
<el-form-item v-if="wxShareForm.isWxShare" label="AppId" prop="mpAppId" :rules="{ required: true, message: '請輸入AppId' }">
<el-input v-model="wxShareForm.mpAppId" placeholder="請輸入AppId"></el-input>
<div class="tips">請進入微信公衆平台,獲取AppId</div>
</el-form-item>
<el-form-item v-if="wxShareForm.isWxShare" label="AppSecret" prop="mpAppSecret" :rules="{ required: true, message: '請輸入AppSecret' }">
<el-input v-model="wxShareForm.mpAppSecret" placeholder="請輸入AppSecret"></el-input>
<div class="tips">請進入微信公衆平台,獲取AppSecret</div>
</el-form-item>
</el-form>
<template v-if="wxShareForm.isWxShare">
<div style="height: 10px"></div>
<el-alert type="info">
請進入微信公衆平台,進入<strong>開發 -> 基本配置 -> IP白名單</strong>,将以(yǐ)下信息填入并啓用。
</el-alert>
<div style="height: 10px"></div>
<el-form size="small" label-width="260px" status-icon>
<el-form-item label="IP白名單">
{{ ipAddress }}
</el-form-item>
</el-form>
</template>
<el-divider></el-divider>
<div style="height: 10px"></div>
<el-row>
<el-col :span="24" align="center">
<el-button type="primary" v-on:click="btnWxShareSubmitClick" size="small">保 存</el-button>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
@section Scripts{
<script src="/assets/share/index.js" type="text/javascript"></script>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
Web API 服務
XYCMS 插件的(de) Web API 開發與 ASP.NET Core 中的(de) Web API 開發同樣無區别,XYCMS 系統啓動時(shí)将自動啓用各個(gè)插件的(de) Web API 功能支持。
關于(yú) Web API 的(de)更多信息可以(yǐ)參考 使用 ASP.NET Core 創建 Web API (opens new window)。
以(yǐ) XYCMS 分享插件 (opens new window)的(de) PingController 爲(wéi / wèi)例,訪問 /api/share/ping 地(dì / de)址獲取結果 pong 以(yǐ)确認插件在(zài)正常運行:
using Microsoft.AspNetCore.Mvc;
namespace XYCMS.Share.Controllers
{
[Route("api/share/ping")]
public class PingController : ControllerBase
{
private const string Route = "";
[HttpGet, Route(Route)]
public string Get()
{
return "pong";
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
以(yǐ) XYCMS 分享插件 (opens new window)的(de) WxController 爲(wéi / wèi)例,訪問地(dì / de)址 /api/share/wx?siteId=<站點Id>&url=<url地(dì / de)址> 将獲取到(dào) JSON 格式的(de)頁面分享信息:
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using XYCMS.Services;
using XYCMS.Share.Abstractions;
namespace XYCMS.Share.Controllers
{
[Route("api/share/wx")]
public partial class WxController : ControllerBase
{
private const string Route = "";
private readonly IWxManager _wxManager;
private readonly IShareManager _shareManager;
public WxController(IWxManager wxManager, IShareManager shareManager)
{
_wxManager = wxManager;
_shareManager = shareManager;
}
public class GetRequest
{
public int SiteId { get; set; }
public string Url { get; set; }
}
public class GetResult
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public string AppId { get; set; }
public string Timestamp { get; set; }
public string NonceStr { get; set; }
public string Signature { get; set; }
}
[HttpGet, Route(Route)]
public async Task<ActionResult<GetResult>> Get([FromQuery] GetRequest request)
{
var success = false;
var errorMessage = string.Empty;
var appId = string.Empty;
var timestamp = string.Empty;
var nonceStr = string.Empty;
var signature = string.Empty;
var settings = await _shareManager.GetSettingsAsync(request.SiteId);
if (settings.IsWxShare)
{
string ticket;
(success, ticket, errorMessage) = await _wxManager.GetJsApiTicketAsync(settings.MpAppId, settings.MpAppSecret);
if (success)
{
appId = settings.MpAppId;
timestamp = _wxManager.GetTimestamp();
nonceStr = _wxManager.GetNonceStr();
signature = _wxManager.GetJsApiSignature(ticket, nonceStr, timestamp, request.Url);
}
}
return new GetResult
{
Success = success,
ErrorMessage = errorMessage,
AppId = appId,
Timestamp = timestamp,
NonceStr = nonceStr,
Signature = signature
};
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
在(zài) Web API 中,我們可以(yǐ)使用預先注入的(de) XYCMS API,更多用法我們将在(zài) XYCMS API 章節中進行詳細說(shuō)明。