using Azure.Core;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using MotorSocialApp.Api.Hubs;
using MotorSocialApp.Application.Features.Group.Command.CreateGroup;
using MotorSocialApp.Application.Features.Group.Command.JoinGroup;
using MotorSocialApp.Application.Features.Group.Command.SendMessageGroup;
using MotorSocialApp.Application.Features.Group.Queries.GetAllChatGroups;
using MotorSocialApp.Application.Features.Group.Queries.GetGroupMessagesByGroupId;
using MotorSocialApp.Application.Features.Group.Queries.GetUserChatGroups;
using MotorSocialApp.Application.Features.Post.Command.CreatePost;
using MotorSocialApp.Application.Features.Post.Queries.GetAllPost;
using MotorSocialApp.Domain.Entities;
using System.Text.RegularExpressions;
namespace MotorSocialApp.Api.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class ChatGroupController : ControllerBase
{
private readonly IMediator _mediator;
private readonly IHubContext<ChatGroupHubService> _hubContext;
public ChatGroupController(IMediator mediator, IHubContext<ChatGroupHubService> hubContext)
{
_mediator = mediator;
this._hubContext = hubContext;
}
[Authorize]
[HttpPost]
public async Task<IActionResult> CreateChatGroup(CreateGroupCommandRequest request)
{
try
{
await _mediator.Send(request);
// SignalR üzerinden istemcilere bildir
await _hubContext.Clients.All.SendAsync("ChatGroup", new
{
Name = request.Name,
GroupIconPath = request.GroupIconPath,
GroupAdminUserId = request.GroupAdminUserId,
GroupDescription = request.GroupDescription,
});
return Ok();
}
catch (Exception ex) { return BadRequest(ex.Message); }
}
[Authorize]
[HttpPost]
public async Task<IActionResult> JoinGroup(JoinGroupCommandRequest request)
{
try
{
await _mediator.Send(request);
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
//[Authorize]
//[HttpPost]
//public async Task<IActionResult> CreateJoinGroupConnection(JoinGroupCommandRequest request)
//{
// try
// {
// return Ok();
// }
// catch (Exception ex)
// {
// return BadRequest(ex.Message);
// }
//}
[Authorize]
[HttpPost]
public async Task<IActionResult> SendMessageGroup(SendMessageGroupRequest request)
{
try
{
await _mediator.Send(request);
// SignalR üzerinden istemcilere bildir
await _hubContext.Clients.Groups(request.GroupId.ToString()).SendAsync("GroupChatMessage", new
{
GroupId = request.GroupId,
SenderUserId = request.SenderUserId,
SenderUserName = request.SenderUserName,
Content = request.Content,
SentAt = request.SentAt,
});
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[Authorize]
[HttpGet]
public async Task<IActionResult> GetAllChatGroups()
{
try
{
var result = await _mediator.Send(new GetAllChatGroupsQueryRequest());
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
//[Authorize]
[HttpGet]
public async Task<IActionResult> GetUserChatGroups(Guid userId)
{
try
{
var result = await _mediator.Send(new GetUserChatGroupsQueryRequest
{
UserId = userId
});
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
//[Authorize]
[HttpGet]
public async Task<IActionResult> GetGroupMessagesByGroupId(Guid groupId)
{
try
{
//await _service.JoinGroup(groupId.ToString());
var result = await _mediator.Send(new GetGroupMessagesByGroupIdQueryRequest
{
GroupId = groupId
});
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
}
using Serilog;
using MotorSocialApp.Persistence;
using MotorSocialApp.Application;
using MotorSocialApp.Infrastructure;
using MotorSocialApp.Application.Exceptions;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.SignalR;
using MotorSocialApp.Api.Hubs; // SignalR için gerekli
var builder = WebApplication.CreateBuilder(args);
// Serilog yapılandırmasını ekleyin
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
// Serilog'u ASP.NET Core'a ekleyin
builder.Host.UseSerilog();
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var env = builder.Environment;
builder.Configuration.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.Services.AddPersistence(builder.Configuration);
builder.Services.AddInfrastructure(builder.Configuration);
builder.Services.AddApplication();
// SignalR Servisini Ekleyin
builder.Services.AddSignalR(options =>
{
// Keep-alive interval: Sunucu, istemciyle bağlantının hala aktif olduğunu göstermek için ping gönderir.
options.KeepAliveInterval = TimeSpan.FromSeconds(15); // Varsayılan: 15 saniye
// Client timeout: İstemci sunucudan ping almazsa bu süre sonunda bağlantının kesildiğini düşünür.
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); // Varsayılan: 30 saniye
});
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MotorSocialApp", Version = "v1", Description = "MotorSocialApp API swagger client." });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "'Bearer' yazip bosluk biraktiktan sonra Token'i girebilirsiniz \r\n\r\n Örnegin: \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\""
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
builder.Services.AddAuthorization();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.ConfigureExceptionHandlingMiddleware();
app.UseStaticFiles();
app.UseRouting();
// CORS Middleware'i buraya ekleyin
app.UseCors("AllowFlutterLocalhost");
app.UseAuthentication(); // Authentication önce
app.UseAuthorization(); // Authorization sonra
// SignalR için Hub Endpoint'i Ekleyin
app.MapHub<ExploreHubService>("/exploreHub");
app.MapHub<ChatGroupHubService>("/chatGroupHub");
app.MapControllers();
app.Run();
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using MotorSocialApp.Domain.Entities;
namespace MotorSocialApp.Api.Hubs
{
public class ChatGroupHubService : Hub
{
// Kullanıcıyı belirli bir gruba katmak
public async Task JoinGroup(string groupId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupId);
}
// Kullanıcıyı bir gruptan çıkarmak
public async Task LeaveGroup(string groupId)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupId);
}
public async Task NewChatGroupMessage(GroupChatMessage message)
{
await Clients.Groups(message.GroupId.ToString()).SendAsync("GroupChatMessage", message);
}
public async Task NewChatGroupMessage1(GroupChatMessage message)
{
await Clients.All.SendAsync("GroupChatMessage1", message);
}
// Yeni bir post eklendiğinde tüm istemcilere bildir.
public async Task NewChatGroup(ChatGroup chatGroup)
{
await Clients.All.SendAsync("ChatGroup", chatGroup);
}
}
}
bunlar benim .net core tarafındaki kodlarım. Burada yapmak istediğim şey aşağıdaki fonksiyonun çalıştırılması
// Kullanıcıyı belirli bir gruba katmak
public async Task JoinGroup(string groupId)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupId);
}
import 'package:flutter/cupertino.dart';
import 'package:moto_kent/constants/api_constants.dart';
import 'package:moto_kent/models/chat_group_message_model.dart';
import 'package:signalr_netcore/signalr_client.dart';
class SignalRMessageService {
late HubConnection _connection;
final VoidCallback? onMessageReceived;
final VoidCallback? onGroupJoined;
final VoidCallback? onGroupLeft;
SignalRMessageService({
this.onMessageReceived,
this.onGroupJoined,
this.onGroupLeft,
});
VoidCallback? onReceivePost;
Future<void> initializeSignalR() async {
// Hub bağlantısını başlat
_connection = HubConnectionBuilder()
.withUrl(ApiConstants.signalRChatGroupEndpoint,
)
.build();
// Bağlantı kapandığında çağrılacak geri çağırım
_connection.onclose(({Exception? error}) {
if (error != null) {
print("SignalR bağlantısı kapandı: ${error.toString()}");
} else {
print("SignalR bağlantısı kapandı.");
}
});
// Grup mesajlarını dinle
_connection.on("GroupChatMessage1", (arguments) async {
if (arguments != null && arguments.isNotEmpty) {
try {
final json = arguments[0] as Map<String, dynamic>;
ChatGroupMessageModel message = ChatGroupMessageModel.fromJson(json);
// Callback ile gelen mesajı işle
onMessageReceived?.call();
print("Yeni mesaj alındı: ${message.content}");
} catch (e) {
print("Mesaj işlenirken hata: $e");
}
}
});
// Bir kullanıcı gruba katıldığında çağrılır
_connection.on("JoinGroup", (arguments) {
print("Bir kullanıcı gruba katıldı: $arguments");
onGroupJoined?.call();
});
// Bir kullanıcı gruptan ayrıldığında çağrılır
_connection.on("LeaveGroup", (arguments) {
print("Bir kullanıcı gruptan ayrıldı: $arguments");
onGroupLeft?.call();
});
try {
await _connection.start();
print("SignalR bağlantısı başarılı.");
} catch (e) {
print("SignalR bağlantı hatası: $e");
}
}
/// Kullanıcıyı bir gruba kat
Future<void> joinGroup(String groupId) async {
if (_connection.state == HubConnectionState.Connected) {
await _connection
.invoke("JoinGroup", args: ["groupId"]);
try {
print("Gruba katılma işlemi başarılı: $groupId");
} catch (e) {
print("Gruba katılma hatası: $e");
}
} else {
print("SignalR bağlantısı aktif değil.");
}
}
/// Kullanıcıyı bir gruptan çıkar
Future<void> leaveGroup(String groupId) async {
if (_connection.state == HubConnectionState.Connected) {
try {
await _connection.invoke("LeaveGroup", args: [groupId]);
print("Gruptan ayrılma işlemi başarılı: $groupId");
} catch (e) {
print("Gruptan ayrılma hatası: $e");
}
} else {
print("SignalR bağlantısı aktif değil.");
}
}
/// Gruba yeni bir mesaj gönder
Future<void> sendMessageToGroup(ChatGroupMessageModel message) async {
if (_connection.state == HubConnectionState.Connected) {
try {
await _connection.invoke("NewChatGroupMessage1", args: [message.toJson()]);
print("Mesaj gruba gönderildi: ${message.content}");
} catch (e) {
print("Mesaj gönderme hatası: $e");
}
} else {
print("SignalR bağlantısı aktif değil.");
}
}
/// Tüm istemcilere yeni bir grup bildirimi gönder
Future<void> notifyNewChatGroup(dynamic chatGroup) async {
if (_connection.state == HubConnectionState.Connected) {
try {
await _connection.invoke("NewChatGroupMessage1", args: [chatGroup]);
print("Yeni grup bildirimi gönderildi.");
} catch (e) {
print("Grup bildirimi gönderme hatası: $e");
}
} else {
print("SignalR bağlantısı aktif değil.");
}
}
/// Bağlantıyı durdur
void dispose() {
_connection.stop();
}
}
flutter tarafında ise signalR için yazdığım servis bu. View sayfamda bu kodları şu şekilde çalıştırıyorum
@override
void initState() {
super.initState();
var viewmodel = context.read<SendMessageViewmodel>();
// Sayfa açıldığında listeyi en sona kaydır
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom();
context.read<SendMessageViewmodel>().fetchMessageList(widget.groupId!);
messageService = SignalRMessageService(
onGroupJoined: () {
print("gruba katıldınız");
},
);
messageService.onReceivePost = () {
setState(() {
// Kaydırma işlemini bir sonraki frame'e planlayarak gerçekleştir
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom();
});
});
};
messageService.initializeSignalR().then((value) {
messageService.joinGroup(widget.groupId!);
},);
});
}
signalR bağlantısı başarılı bir şekilde gerçekleşiyor yani flutter tarafında yazdığım signalR servisini bu kısmı düzgün çalışıyor
try {
await _connection.start();
print("SignalR bağlantısı başarılı."); //>> bu çıktıyı alıyorum
} catch (e) {
print("SignalR bağlantı hatası: $e");
}
fakat
/// Kullanıcıyı bir gruba kat
Future<void> joinGroup(String groupId) async {
if (_connection.state == HubConnectionState.Connected) {
await _connection
.invoke("JoinGroup", args: ["groupId"]);
try {
print("Gruba katılma işlemi başarılı: $groupId");
} catch (e) {
print("Gruba katılma hatası: $e");
}
} else {
print("SignalR bağlantısı aktif değil.");
}
}
fonksiyonum çalışmaya başladığında
E/flutter ( 6674): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Server returned an error on close: Connection closed with an error.
bu hatayı alıyorum . Bu sorunu bir türlü çözemedim . Gruplara ayırmadığımda ve controllerde
[Authorize]
[HttpPost]
public async Task<IActionResult> SendMessageGroup(SendMessageGroupRequest request)
{
try
{
await _mediator.Send(request);
// SignalR üzerinden istemcilere bildir
await _hubContext.Clients.Groups(request.GroupId.ToString()).SendAsync("GroupChatMessage", new
{
GroupId = request.GroupId,
SenderUserId = request.SenderUserId,
SenderUserName = request.SenderUserName,
Content = request.Content,
SentAt = request.SentAt,
});
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
bu kod yerine
[Authorize]
[HttpPost]
public async Task<IActionResult> SendMessageGroup(SendMessageGroupRequest request)
{
try
{
await _mediator.Send(request);
// SignalR üzerinden istemcilere bildir
await _hubContext.Clients.All.SendAsync("GroupChatMessage", new
{
GroupId = request.GroupId,
SenderUserId = request.SenderUserId,
SenderUserName = request.SenderUserName,
Content = request.Content,
SentAt = request.SentAt,
});
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
bunu kullanıp tüm istemcilere mesaj gönderebiliyorum . Yukarıda bahsettiğim sorunu nasıl çözebilirim daha önce buna benzer bir hata aldınız mı ?