C# Blazor wasm Web API响应是一个HTML字符串
好的,我有一个wasm应用程序,它调用服务器端web api端点。 问题是我从/wwwroot目录中获取端点的index.html页面作为答案。但是当我用Postman处理端点时,我得到了预期的json答案。 好的,我将展示如何使用我的代码实现这一点 客户端数据流 搜索网页 在这里,当在表单字段中输入搜索文本时,我调用Web API端点。这是意料之中的事C# Blazor wasm Web API响应是一个HTML字符串,c#,asp.net-core,blazor-webassembly,C#,Asp.net Core,Blazor Webassembly,好的,我有一个wasm应用程序,它调用服务器端web api端点。 问题是我从/wwwroot目录中获取端点的index.html页面作为答案。但是当我用Postman处理端点时,我得到了预期的json答案。 好的,我将展示如何使用我的代码实现这一点 客户端数据流 搜索网页 在这里,当在表单字段中输入搜索文本时,我调用Web API端点。这是意料之中的事 ... Snip // UPDATED INFO <div class="form-group">
... 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);
}
}
}
服务器端数据流
DDS DashboardController.cs作为Web API控制器
当我与邮递员联系时,该控制器中的所有方法(路由)都能完美地工作
路由[HttpGet(“GetDddsObjectAttributeValueCount”)]
和路由[HttpGet(“GetDddsObjectTypeStatistic”)]
也与服务器ApiclientService.cs一起工作
只有路由[HttpGet(“searchObjectsByNamePhase/{objTypeId}/{searchTerm}”)]只能在邮递员中工作
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
}
}
配置服务方法
如果有人知道如何在渲染时使用foreach循环设置值,我将非常高兴听到这个消息
感谢@Neil W的帮助。我无法直接回答您的问题,但当我第一次遇到Blazor wasm client的WebAPI挑战时,我创建了一个客户端API基类,因此:
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);
}
}
公共抽象类ClientAPI
{
受保护的只读HttpClient Http;
私有只读字符串基路由;
受保护的客户端API(字符串基路由,HttpClient http)
{
BaseRoute=BaseRoute;
Http=Http;
}
受保护的异步任务GetAsync(string relativeUri)
=>等待进程HttpResponse(等待Http.GetAsync($“{BaseRoute}/{relativeUri}”);
受保护的异步任务PostAsync(字符串relativeUri、TRequest请求)
=>等待ProcessHttpResponse(等待Http.postsJSonAsync($“{BaseRoute}/{relativeUri}”,请求));
专用静态异步任务进程HttpResponse(HttpResponseMessage响应)
{
if(响应。IsSuccessStatusCode)
return wait response.Content.ReadFromJsonAsync();
string msg=wait response.Content.ReadAsStringAsync();
控制台写入线(msg);
抛出新异常(msg);
}
}
然后,我的派生客户端API类将在基类上调用GetAsync。这将解析Json响应,或者如果HttpResponseMessage具有故障状态代码,它将记录错误
从派生类中使用,如下所示:
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);
public类BackOfficeClientAPI:ClientAPI
{
公共BackOfficeClientAPI(HttpClient-http):base(“api/backoffice”,http){}
公共异步任务GetCategoriesAsync(Guid OrganizationID)
=>等待GetAsync($“getcategories?OrganizationId={OrganizationId}”);
公共异步任务AddCategoryAsync(AddCategoryRequest请求)
=>等待PostAsync(“添加类别”,请求);
另外,我使用querystring代替路由参数,但原理是一样的
我发现捕获这种类型的异常是一种很好的模式。首先尝试将客户端PI中的结果放入HttpResponseMessage。然后检查它。您返回的状态代码是什么?>>>>HttpResponseMessage res=wait(u httpClient.GetAsync($“/api/DDSDoard/SearchObjectsBynamephase/{objTypeUuid})/{searchTermPhrase}”);>>>这可能会给你一个线索。谢谢Neil W。他们真的给了你一个提示。
{objTypeUuid}
没有设置初始值。我会更新我的问题。谢谢这个模式。这是个好主意。
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>
protected override async Task OnInitializedAsync()
{
_objectTypes = await DdsApiClient.GetObjectTypes();
_searchByNameObjectTypeUuid = _objectTypes.SingleOrDefault(x => x.TypeName == "Music")?.Uuid.ToString("D");
}
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);
}
}
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);