我目前正在开发一个 ASP.NET Core 项目,并尝试添加部分视图。但是,我遇到了与 Bootstrap 版本控制相关的错误。错误消息指出:
我已经验证我的项目使用的是 Bootstrap v4.1.3,如 bootstrap.css 文件中所示。尽管如此,我在尝试添加部分视图时仍然收到错误。而且我也尝试升级 bootstrap 版本。
当我尝试在 ASP.NET Core 项目中添加部分视图时,如何解决此 Bootstrap 版本错误?如能提供任何指导或建议,我将不胜感激!
我正在开发针对 .NET 9 的 Blazor WASM(独立)应用程序中的自动完成组件版本。
我能够使用以下代码将 绑定input
到string
变量并在用户输入其搜索关键字时采取行动,并且它工作正常,但是当我尝试将自动完成的 UI 移动到组件中时,将 绑定到我的变量似乎不起作用。该部件继续正常工作,并且我在每次击键后都会点击我的方法。@bind:after
input
bind:after
这是运行良好的代码,然后我将其移入一个组件:
...
<input @bind="UserInputText" @bind:event="oninput" @bind:after="OnUserInputChanged" />
...
@code {
private string? UserInputText = "";
private void OnUserInputChanged()
{
// Process user input and make suggestions
}
}
然后,我将 UI 部分放入我正在创建的新组件中,以将自动完成功能封装到其自己的组件中。
这是父代码:
...
<AutoComplete UserInputText="UserInput" UserInputTextChangedHandler="OnUserInputChanged" />
...
@code {
private string? UserInput = "";
private void OnUserInputChanged()
{
// Process user input and make suggestions
}
}
以下是组件内部的代码AutoComplete
:
@typeparam TItem
<div>
<input @bind="UserInputText" @bind:event="oninput" @bind:after="UserInputTextChangedHandler" />
</div>
@code {
[Parameter]
public string? UserInputText { get; set; }
[Parameter]
public Action UserInputTextChangedHandler { get; set; }
[Parameter]
public List<TItem> Suggestions { get; set; }
}
顺便说一句,我尝试使用EventCallback
而不是Action
传递OnUserInputChanged
给自动完成组件,但随后收到一条错误,指出:
参数 1:无法从“Microsoft.AspNetCore.Components.EventCallback”转换为“System.Action”
还请记住,OnUserInputChanged
即使我将该逻辑放入新组件中,接线实际上仍能正常工作。不再起作用的部分是绑定UserInputText
到input
组件内部。
我哪里犯了错误?
我的 Blazor WASM 独立应用程序(针对 .NET 9)中有一个简单的应用程序select
,我想在用户选择一个选项后执行一些操作。我了解对于async
调用,Microsoft 现在建议使用bind:after
。
我按照这个视频DoSomething()
操作,并按照他在教程中所做的操作,但在我的例子中,我没有达到我在代码中设置的方法中的断点。我在这里做错了什么?
<div>
<select @bind="SelectedState" @bind:after="DoSomething">
<option value="">Please select one</option>
<option value="AK">Alaska</option>
<option value="MT">Montana</option>
<option value="WY">Wyoming</option>
</select>
</div>
@code {
private string SelectedState;
private async Task DoSomething()
{
var userSelected = SelectedState; // Have a break point here but don't hit it
}
}
当我创建新的 Blazor Web App 时,服务器和客户端项目都包含一个 program.cs 文件,正如预期的那样。我是否需要在两个 program.cs 文件中配置依赖项容器,一次在服务器项目中,一次在客户端项目中?
我已经将容器添加到两个文件中,但似乎有很多代码重复。是否有一个项目结构只需要将容器放在一个地方,而不管它们被注入到哪里。我正在使用 Clean Architecture。
我最初将所有容器都放在服务器项目中,但出现了“没有注册服务”的错误,如果我将它们全部放在客户端项目中,也会出现同样的错误。
我肯定做错了什么,对吧?
需要一些帮助。Razor 组件的新手。我有一个托管发票的 Razor 页面,其中的一个子部分是付款。我创建了一个 Razor 组件来处理付款并更新名为 CurrentModel 的属性。我想返回对实例化 Razor 组件的 Razor 页面所做的更改。我想我可以通过将组件参数设置为方法来做到这一点(基于https://learn.microsoft.com/en-us/aspnet/core/blazor/components/event-handling?view=aspnetcore-9.0#eventcallback)。
成分:
[Parameter]
public EventCallback<List<Partial>> TestCallBack { get; set; }
然后稍后在组件中:
private async Task SetAmount(ChangeEventArgs e, int paymentId)
{
var amount = e.Value.ToDecimal();
if (amount.HasValue)
{
CurrentModel = CurrentModel.SetAmount(paymentId, amount.Value, Validator);
}
await TestCallBack.InvokeAsync(CurrentModel);
}
Razor Page 中的组件声明:
<component type="typeof(Components.Invoices.Payments)" render-mode="ServerPrerendered" param-testcallback="@Model.ReturnCallBack" />
(也尝试过)
<component type="typeof(Components.Invoices.Payments)" render-mode="ServerPrerendered" TestCallBack="@Model.ReturnCallBack" />
public async Task ReturnCallBack(List<Partial> partials)
{
...
}
无论哪种方式,VS 都会告诉我:
答案当然是肯定的,我确实希望调用该方法,但我不知道如何让该方法一直有效。上面的内容似乎使委托无效。
我的方法不是标准方法吗?我是否应该遵循其他方法?
我期望这种方法能够奏效,但是有些事情阻碍了委派。
当使用 EF Core DB 优先方法时,默认视图不显示主键。如何控制视图中显示哪些数据?
我搜索了模板和生成的代码。我搜索了 EF Core 教程和示例。
我刚刚创建了一个新的 .net blazor web 应用项目并添加了此代码
@page "/weather"
@attribute [StreamRendering] @rendermode InteractiveServer <PageTitle>Weather</PageTitle>
<h1>Weather</h1>
@using System.Diagnostics
<h3>Dropdown Example</h3>
<select @bind="SelectedSet" class="form-select">
<option disabled selected value="">-- Select a Set --</option>
@foreach (var set in Sets)
{
<option value="@set">@set</option>
} </select> <p>You selected: @SelectedSet</p>
<div class="mb-3">
<label for="SetType" class="form-label">Set Type</label>
<InputSelect id="SetType" @bind-Value="CollectionSet" class="form-select">
@foreach (var set in Sets)
{
<option value="@set">@set</option>
}
</InputSelect> </div> <p>You selected: @CollectionSet</p>
@code {
private List<string> Sets = new List<string> { "Pad", "Leather", "Bronze" };
private string SelectedSet { get; set; }
private string CollectionSet { get; set; }
private void OnSetChanged(ChangeEventArgs e)
{
Debug.WriteLine($"Selected value changed to: {SelectedSet}");
// Additional logic can be added here
} }
但是当我在方法上设置断点时,它就是不起作用。我不明白为什么事件没有触发。起初我使用枚举,我以为是因为这个原因,但对于一个简单的字符串,它仍然不起作用
我们正在使用 MS 为 ASP.NET Core API 应用程序提供的全新 OpenAPI 开箱即用支持,但在生成 json 的方式上遇到了一些问题。我们有以下类型:
public class MsgMovimentacaoLocaisTrabalho {
public IList<InfoGeral>? LocaisRemover { get; set; }
public InfoGeral? LocaisAssociar { get; set; }
}
public class InfoGeral {
public Guid GuidDirecao { get; set; }
public IEnumerable<int> Locais { get; set; } = Enumerable.Empty<int>();
}
MsgMovimentacaoLocaisTrabalho
用作控制器方法之一的参数类型:
public async Task<IActionResult> MovimentaLocaisTrabalhoAsync(
[Description("Mensagem que ....")]MsgMovimentacaoLocaisTrabalho msg,
CancellationToken cancellationToken) {
...
问题在于类型的输出:
...
"MsgMovimentacaoLocaisTrabalho": {
"type": "object",
"properties": {
"locaisRemover": {
"type": "array",
"items": {
"$ref": "#/components/schemas/InfoGeral"
},
"nullable": true
},
"locaisAssociar": {
"$ref": "#/components/schemas/InfoGeral2"
}
}
},
"InfoGeral": {
"type": "object",
"properties": {
"guidDirecao": {
"type": "string",
"format": "uuid"
},
"locais": {
"type": "array",
"items": {
"type": "integer",
"format": "int32"
}
}
}
},
....
"InfoGeral2": {
"type": "object",
"properties": {
"guidDirecao": {
"type": "string",
"format": "uuid"
},
"locais": {
"$ref": "#/components/schemas/#/properties/locaisRemover/items/properties/locais"
}
},
"nullable": true
},
首先,查看InfoGeral
架构,它看起来不错(locais
表示为 的数组int
),但我不确定为什么会有类型InfoGeral2
。我假设这是因为该类型MsgMovimentacaoLocaisTrabalho
有 2 个引用该类型的属性...
第一个问题:有没有办法让这两个属性的架构重用InfoGeral
?
问题 2:为什么我最终得到的是错误的值locais
而不是数组?IEnumerable 不应该在架构上生成数组吗?
顺便说一句,这是错误:
Semantic error at components.schemas.InfoGeral2.properties.locais.$ref
$ref values must be RFC3986-compliant percent-encoded URIs
Jump to line 11623
我有以下项目结构:
在 Project AI 中,登录的具体实现如下:
public async Task LoginUser()
{
if (Input.Username == "" && Input.Email == "")
{
errorMessage = "Username or Email is required for sign in";
return;
}
if (Input.Password == "")
{
errorMessage = "Password is required for sign in";
return;
}
try
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
ApplicationUser? userObj;
if (emailUsername_Switch)
userObj = await UserManager.FindByEmailAsync(Input.Email);
else
userObj = await UserManager.FindByNameAsync(Input.Username);
if (userObj == null)
{
errorMessage = "Unable to find user in the system. Please Register or check username/email.";
return;
}
Guid userId = new Guid();
if (userObj != null)
{
userId = userObj.Id;
}
isLoading = true;
if (await SignInManager.CanSignInAsync(userObj))
{
var result = await SignInManager.CheckPasswordSignInAsync(userObj, Input.Password, true);
if (result == Microsoft.AspNetCore.Identity.SignInResult.Success)
{
Guid key = Guid.NewGuid();
BlazorCookieLoginMiddleware.Logins[key] = new LoginInfo { Email = userObj.Email, UserName = userObj.UserName, Password = Input.Password };
// Generate JWT Token
var token = TokenService.GenerateToken(Input.Username);
// Store token in localStorage (or use other storage methods as required)
// Save the token to localStorage
await LocalStorageService.SetItemAsync("jwt_token", token);
NavigationManager.NavigateTo($"/login?key={key}", true);
}
else if (result == Microsoft.AspNetCore.Identity.SignInResult.LockedOut)
{
errorMessage = "User account locked please contact administrator";
}
else if (result == Microsoft.AspNetCore.Identity.SignInResult.Failed)
{
// Handle failure
// Get the number of attempts left
var attemptsLeft = UserManager.Options.Lockout.MaxFailedAccessAttempts - await UserManager.GetAccessFailedCountAsync(userObj);
errorMessage = $"Invalid Login Attempt. Remaining Attempts : {attemptsLeft}";
}
}
else
{
errorMessage = "Your account is blocked";
}
}
catch (Exception ex)
{
errorMessage = "Error: Invalid login attempt. Please check again.";
}
isLoading = false;
}
以下是我的TokenService:
public class TokenService
{
private readonly string _secretKey;
private readonly string _issuer;
private readonly string _audience;
public TokenService(string secretKey, string issuer, string audience)
{
_secretKey = secretKey;
_issuer = issuer;
_audience = audience;
}
// Method to generate JWT token
public string GenerateToken(string username)
{
var claims = new[]
{
new Claim(ClaimTypes.Name, username),
// Add other claims as needed
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _issuer,
audience: _audience,
claims: claims,
expires: DateTime.Now.AddHours(1),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
// Method to validate token and extract user info
public ClaimsPrincipal ValidateToken(string token)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
var handler = new JwtSecurityTokenHandler();
try
{
var principal = handler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer = _issuer,
ValidAudience = _audience,
IssuerSigningKey = key
}, out var validatedToken);
return principal;
}
catch
{
return null;
}
}
}
在 Project BI 中,SignalR 有以下实现:
[Authorize]
public class NotificationHub : Hub
{
private static readonly ConcurrentDictionary<string, List<string>> UserConnections = new();
[Authorize]
public override Task OnConnectedAsync()
{
var userEmail = Context.User?.FindFirst(ClaimTypes.Email)?.Value;
//var userName = Context.User?.Identity?.Name; // Assuming the username is stored in the Name claim
if (!string.IsNullOrEmpty(userEmail))
{
UserConnections.AddOrUpdate(
userEmail,
new List<string> { Context.ConnectionId }, // Add a new list with the current connection ID
(key, existingConnections) =>
{
if (!existingConnections.Contains(Context.ConnectionId))
{
existingConnections.Add(Context.ConnectionId); // Add the connection ID to the existing list
}
return existingConnections;
});
}
return base.OnConnectedAsync();
}
[Authorize]
public override Task OnDisconnectedAsync(Exception exception)
{
var userEmail = Context.User?.FindFirst(ClaimTypes.Email)?.Value;
var connectionID = Context.ConnectionId;
if (!string.IsNullOrEmpty(userEmail))
{
if (UserConnections.TryGetValue(userEmail, out var connections))
{
// Remove the specific connection ID
connections.Remove(Context.ConnectionId);
// If no more connections exist for this user, remove the user entry from the dictionary
if (connections.Count == 0)
{
UserConnections.TryRemove(userEmail, out _);
}
}
}
return base.OnDisconnectedAsync(exception);
}
[Authorize]
public async Task SubscribeToTouchSiteGroup(Guid siteId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, SignalR_Method.TouchSiteGroup + "_" + siteId);
}
[Authorize]
public async Task UnSubscribeFromTouchSiteGroup(Guid siteId)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, SignalR_Method.TouchSiteGroup + "_" + siteId);
}
}
JWT 本地存储服务:
public class LocalStorageService
{
private readonly IJSRuntime _jsRuntime;
public LocalStorageService(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public async Task SetItemAsync(string key, string value)
{
await _jsRuntime.InvokeVoidAsync("localStorageHelper.setItem", key, value);
}
public async Task<string> GetItemAsync(string key)
{
return await _jsRuntime.InvokeAsync<string>("localStorageHelper.getItem", key);
}
public async Task RemoveItemAsync(string key)
{
await _jsRuntime.InvokeVoidAsync("localStorageHelper.removeItem", key);
}
public async Task ClearAsync()
{
await _jsRuntime.InvokeVoidAsync("localStorageHelper.clear");
}
}
JWT 本地存储的 JS 脚本:
//////////////////////////////////Code for JWT Local Storage///////////////////////////////////////////
window.localStorageHelper = {
setItem: function (key, value) {
localStorage.setItem(key, value);
},
getItem: function (key) {
return localStorage.getItem(key);
},
removeItem: function (key) {
localStorage.removeItem(key);
},
clear: function () {
localStorage.clear();
}
};
然后,我有用于共享数据和启动 SignalR 连接的集中服务:(字符串 baseUrl、字符串 hubPath)作为参数从每个应用程序传递,指定打开 hubconnection 进行接收。意味着项目 C 将为项目 D baseURL 打开。
public class ProductNotificationHubService
{
private readonly LocalStorageService _localStorageService;
private HubConnection? _hubConnection;
/// <summary>
///
/// </summary>
/// <param name="cacheService"></param>
/// <param name="productService"></param>
/// <param name="lockManagerService"></param>
public ProductNotificationHubService(LocalStorageService localStorageService)
{
_localStorageService = localStorageService;
}
/// <summary>
///
/// </summary>
/// <param name="baseUrl"></param>
/// <param name="hubPath"></param>
/// <param name="subscribeToGroup"></param>
/// <param name="siteId"></param>
/// <param name="userName"></param>
/// <returns></returns>
public async Task<bool> InitializeHubAsync(string baseUrl, string hubPath, string subscribeToGroup, Guid? siteId, string userName)
{
UserName = userName;
// Retrieve token from localStorage
var token = await _localStorageService.GetItemAsync("jwt_token");
// Initialize the SignalR connection and pass the token
_hubConnection = new HubConnectionBuilder()
.WithUrl(new Uri(new Uri(baseUrl), hubPath), options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
})
.WithAutomaticReconnect()
.Build();
_hubConnection.On<Guid?, ProductModel, string>(SignalR_Method.TouchProductReceiveNotification, async (siteID, product, messageType) =>
{
if (_subscribedMessageTypes.Contains(messageType))
{
await HandleNotificationAsync(siteID, product, messageType);
}
});
try
{
await _hubConnection.StartAsync();
await _hubConnection.InvokeAsync(subscribeToGroup, siteId);
return true;
}
catch (Exception ex)
{
return false;
// Handle exception (e.g., log it)
}
}
}
现在在项目 C 和项目 DI 中调用和启动 signalR 连接时有以下代码:
var baseUrl = "https://localhost:7140"; // Project D's URL in project C for listening
var hubPath = "/notificationHub"; // Path to your hub
await ProductNotificationHubService.InitializeHubAsync(baseUrl, hubPath, SignalR_Method.SubscribeToTouchSiteGroup, Site.Site_ID, _userInfo.UserName)
以下是项目 D 和项目 C 的 Program.cs 文件:
builder.Services.AddScoped<LocalStorageService>();
// Register TokenService directly
builder.Services.AddSingleton<TokenService>(provider =>
new TokenService(
builder.Configuration.GetSection("TokenSettings").GetValue<string>("Key"),
builder.Configuration.GetSection("TokenSettings").GetValue<string>("Issuer"),
builder.Configuration.GetSection("TokenSettings").GetValue<string>("Audience")
));
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
options.RequireAuthenticatedSignIn = true;
})
// Cookie based authentication for login validation
.AddCookie(options =>
{
options.LoginPath = "/Account/Login/";
options.LogoutPath = "/Account/Logout/";
options.AccessDeniedPath = "/Account/AccessDenied";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.Cookie.HttpOnly = true;
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromSeconds(30);
})
// JWT Bearer Authentication for API or SignalR clients
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = builder.Configuration.GetSection("TokenSettings").GetValue<string>("Issuer"),
ValidateIssuer = true,
ValidAudience = builder.Configuration.GetSection("TokenSettings").GetValue<string>("Audience"),
ValidateAudience = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection("TokenSettings").GetValue<string>("Key"))),
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
options.IncludeErrorDetails = true;
// Use Authorization header for SignalR
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// Extract token from query string for SignalR
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
}).AddIdentityCookies();
现在请注意,我当前的身份验证适用于使用 cookies 身份验证的两个应用程序,我想继续使用。只想对 SignalR 使用 JWT 身份验证才能获取上下文详细信息(var userEmail = Context.User?.FindFirst(ClaimTypes.Email)?.Value;
)。
现在我面临的问题仍然是相同的,JWT 令牌被添加到本地存储,但是在 Program.cs 文件中,我总是得到下面的空字符串:
// Extract token from query string for SignalR
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
并且上下文仍然空白,我觉得我遗漏了一些东西,请指教?