[英]Blazor wasm Web API response is an HTML string
好的,我有一個調用服務器端 web api 端點的 wasm 應用程序。 問題是我從端點的 /wwwroot 目錄中獲取 index.html 頁面作為答案。 但是當我使用 Postman 尋址端點時,我得到了 json 的預期答案。 好的,我將展示如何使用我的代碼執行此操作。
在這里,當在表單字段中輸入搜索文本時,我調用 Web API 端點。 這按預期工作。
... Snip
// UPDATED INFO
<div class="form-group">
<label for="objectType">Select object type</label>
<select id="objectType" class="form-control" @bind="@_searchByNameObjectTypeUuid">
@if (_objectTypes != null)
{
@foreach (var objectType in _objectTypes)
{
@if (objectType.TypeName == "Music")
{
@* This selection value is not set. But why?
<option value="@objectType.Uuid.ToString("D")" selected="selected">@objectType.TypeName</option>
}
else
{
<option value="@objectType.Uuid.ToString("D")">@objectType.TypeName</option>
}
}
}
</select>
</div>
// UPDATED INFO END
<div class="form-group">
<label for="objectName">Object name:<br/></label>
<input type="text" class="form-control" id="objectName" @onkeydown="@SearchByNameOnEnter" @bind-value="@_searchByNameObjectNamePhrase" @bind-value:event="oninput"/>
</div>
...Snip
@code {
private string _searchByNameObjectNamePhrase = string.Empty;
private async Task SearchByNameOnEnter(KeyboardEventArgs e)
{
if ((e.Code == "Enter" || e.Code == "NumpadEnter") && !string.IsNullOrWhiteSpace(_searchByNameObjectNamePhrase))
{
_searchResult = await ServerApiClient.SearchObjectsByNamePhrase(_searchByNameObjectTypeUuid, _searchByNameObjectNamePhrase);
}
}
}
有了這個,我調用了不同的 Web API 端點,它們從后端的數據庫中獲取數據。
GetDdsObjectAttributeValueCount()
方法按預期工作。
SearchObjectsByNamePhrase(string objTypeUuid, string searchTermPhrase)
方法將文件 /wwwroot/index.html 作為答案發送給我。 (在代碼中顯示注釋以獲取詳細信息)
namespace WebAssembly.Client.Services
{
public class ServerApiClientService : IServerApiClientService
{
#region Constants - Static fields - Fields
private readonly HttpClient _httpClient;
#endregion
#region Constructors and Destructors
public ServerApiClientService(HttpClient httpClient)
{
_httpClient = httpClient;
}
#endregion
#region Methods
// This endpoint request work as expected
public async Task<IEnumerable<ObjectAttributeValueCount>> GetDdsObjectAttributeValueCount()
{
IEnumerable<ObjectAttributeValueCount> result =
await _httpClient
.GetFromJsonAsync<List<ObjectAttributeValueCount>>("/api/DdsDashboard/GetDdsObjectAttributeValueCount");
return (result ?? Array.Empty<ObjectAttributeValueCount>()).AsQueryable();
}
// This endpoint request NOT work as expected
public async Task<IEnumerable<SearchResultItem>> SearchObjectsByNamePhrase(string objTypeUuid, string searchTermPhrase)
{
// For test i have called as string and i get HTML response. wwwroot/index.html is comming back.
var asJsonString =
await _httpClient
.GetStringAsync($"/api/DdsDashboard/SearchObjectsByNamePhrase/{objTypeUuid}/{searchTermPhrase}");
// And here i get the exception "System.Text.Json.JsonReaderException"
// '<' is an invalid start of a value
IEnumerable<SearchResultItem> result =
await _httpClient
.GetFromJsonAsync<List<SearchResultItem>>($"/api/DdsDashboard/SearchObjectsByNamePhrase/{objTypeUuid}/{searchTermPhrase}");
return (result ?? Array.Empty<SearchResultItem>()).AsQueryable();
}
#endregion
}
}
當我使用 Postman 解決這些問題時,此 controller 中的所有方法(路線)都能正常工作。
路由[HttpGet("GetDdsObjectAttributeValueCount")]
和路由[HttpGet("GetDdsObjectTypeStatistic")]
也適用於 ServerApiClientService.cs。
只有路線 [HttpGet ("SearchObjectsByNamePhrase / {objTypeId} / {searchTerm}")] 僅適用於 Postman。
namespace WebAssembly.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DdsDashboardController : ControllerBase
{
#region Constants - Static fields - Fields
private readonly IDdsRepository _repository;
#endregion
#region Constructors and Destructors
public DdsDashboardController(IDdsRepository repo)
{
_repository = repo;
}
#endregion
#region Methods
[HttpGet("GetDdsObjectAttributeValueCount")]
public async Task<IEnumerable<ObjectAttributeValueCount>> GetDdsObjectAttributeValueCount()
{
return await _repository.GetDdsObjectAttributeValueCount();
}
[HttpGet("GetDdsObjectTypeStatistic")]
public async Task<IEnumerable<ObjectTypeStatistic>> GetDdsObjectTypeStatistic()
{
return await _repository.GetDdsObjectTypeStatistic();
}
// This method is called and worked as expected. When i call this endpoint with Postman all is fine. Correct JSON response.
[HttpGet("SearchObjectsByNamePhrase/{objTypeId}/{searchTerm}")]
public async Task<IEnumerable<SearchResultItem>> SearchObjectsByNamePhrase(string objTypeId, string searchTerm)
{
// Correct result from my database. I have checked with an breakpoint.
var result = await _repository.SearchObjectsByNamePhrase(objTypeId, searchTerm);
return result;
}
#endregion
}
}
public void Configure(IApplicationBuilder app)
{
if (Env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
public void ConfigureServices(IServiceCollection services)
{
SqlMapper.AddTypeHandler(new MySqlGuidTypeHandler());
SqlMapper.RemoveTypeMap(typeof(Guid));
SqlMapper.RemoveTypeMap(typeof(Guid?));
services.AddControllersWithViews();
services.AddRazorPages();
services.AddScoped<IDdsRepository, DdsRepository>();
var dbConnectionSettings = new DdsDbConnectionConfiguration(Configuration.GetSection("DdsDbSettings"));
services.AddSingleton(dbConnectionSettings);
if (!Env.IsDevelopment())
{
services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
}
}
我希望我已經提供了足夠的信息,以便能夠告訴我為什么這不起作用。
好的。 問題是表單控件的綁定僅在我手動進行選擇更改時才起作用。 在渲染不工作時設置一個選定項。
<div class="form-group">
<label for="objectType">Select object type</label>
<select id="objectType" class="form-control" @bind="@_searchByNameObjectTypeUuid">
@if (_objectTypes != null)
{
@foreach (var objectType in _objectTypes)
{
@if (objectType.TypeName == "Music")
{
<option value="@objectType.Uuid.ToString("D")" selected="selected">@objectType.TypeName</option>
}
else
{
<option value="@objectType.Uuid.ToString("D")">@objectType.TypeName</option>
}
}
}
</select>
</div>
這就是未設置_searchByNameObjectTypeUuid
值的原因。 並使用該endpoints.MapFallbackToFile(" index.html ")
。
我在OnInitializedAsync()
方法中設置了_searchByNameObjectTypeUuid
的值,我還加載了_objectTypes
。
protected override async Task OnInitializedAsync()
{
_objectTypes = await DdsApiClient.GetObjectTypes();
_searchByNameObjectTypeUuid = _objectTypes.SingleOrDefault(x => x.TypeName == "Music")?.Uuid.ToString("D");
}
如果有人知道如何在渲染時使用 foreach 循環設置值,我將不勝感激。
感謝@Neil W 的幫助。
我沒有直接回答您的問題,但是當我第一次開始遇到來自 Blazor wasm 客戶端的 WebAPI 挑戰時,我創建了一個客戶端 API 基礎 class,因此:
public abstract class ClientAPI
{
protected readonly HttpClient Http;
private readonly string BaseRoute;
protected ClientAPI(string baseRoute, HttpClient http)
{
BaseRoute = baseRoute;
Http = http;
}
protected async Task<TReturn> GetAsync<TReturn>(string relativeUri)
=> await ProcessHttpResponse<TReturn>(await Http.GetAsync($"{BaseRoute}/{relativeUri}"));
protected async Task<TReturn> PostAsync<TReturn, TRequest>(string relativeUri, TRequest request)
=> await ProcessHttpResponse<TReturn>(await Http.PostAsJsonAsync($"{BaseRoute}/{relativeUri}", request));
private static async Task<TReturn> ProcessHttpResponse<TReturn>(HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
return await response.Content.ReadFromJsonAsync<TReturn>();
string msg = await response.Content.ReadAsStringAsync();
Console.WriteLine(msg);
throw new Exception(msg);
}
}
然后我的派生客戶端 API class 將在基礎 class 上調用 GetAsync。 然后,這將解決 Json 響應,或者如果 HttpResponseMessage 有失敗狀態代碼,它將記錄錯誤。
從派生的 class 使用,如下所示:
public class BackOfficeClientAPI : ClientAPI
{
public BackOfficeClientAPI(HttpClient http) : base("api/backoffice", http) { }
public async Task<IEnumerable<Category>> GetCategoriesAsync(Guid organisationId)
=> await GetAsync<IEnumerable<Category>>($"getcategories?organisationId={organisationId}");
public async Task<Category> AddCategoryAsync(AddCategoryRequest request)
=> await PostAsync<Category, AddCategoryRequest>("addcategory", request);
PS。 我使用的是查詢字符串而不是路由參數,但原理是一樣的。
我發現捕獲這種類型的異常是一個很好的模式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.