Fix AlarmService.cs duplicate definitions

- Rewrote AlarmService.cs to only contain IAlarmService and AlarmManager
- Removed duplicate AlarmRuleService, AlarmNotificationService definitions
- Removed duplicate IEmailService, ISmsService, IWechatService, IAlarmRuleRepository, IAlarmNotificationRepository

Note: Haoliang.Core still has many errors due to:
- Duplicate class definitions in SystemService.cs, TemplateService.cs, TemplateValidationService.cs, ServiceInfrastructure.cs
- Missing types (DeviceState, NotificationChannel, etc.)
- Ambiguous type references (TagData, DeviceCurrentStatus)
main
821644@qq.com 3 weeks ago
parent 816621dcb9
commit a7881ff7d0

@ -28,32 +28,6 @@ namespace Haoliang.Core.Services
Task<IEnumerable<Alarm>> GetDeviceAlarmsAsync(int deviceId, int days = 7); Task<IEnumerable<Alarm>> GetDeviceAlarmsAsync(int deviceId, int days = 7);
} }
public interface IAlarmRuleService
{
Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule);
Task<AlarmRule> UpdateAlarmRuleAsync(int ruleId, AlarmRule rule);
Task<bool> DeleteAlarmRuleAsync(int ruleId);
Task<AlarmRule> GetAlarmRuleByIdAsync(int ruleId);
Task<IEnumerable<AlarmRule>> GetAllAlarmRulesAsync();
Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync();
Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId);
Task<bool> EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status);
Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status);
Task TestAlarmRuleAsync(int ruleId);
}
public interface IAlarmNotificationService
{
Task SendAlarmNotificationAsync(Alarm alarm);
Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms);
Task<bool> SendSmsNotificationAsync(string phoneNumber, string message);
Task<bool> SendEmailNotificationAsync(string email, string subject, string message);
Task<bool> SendWechatNotificationAsync(string openId, string message);
Task<IEnumerable<AlarmNotification>> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate);
Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel);
Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync();
}
public class AlarmManager : IAlarmService public class AlarmManager : IAlarmService
{ {
private readonly IAlarmRepository _alarmRepository; private readonly IAlarmRepository _alarmRepository;
@ -72,14 +46,11 @@ namespace Haoliang.Core.Services
public async Task<Alarm> CreateAlarmAsync(Alarm alarm) public async Task<Alarm> CreateAlarmAsync(Alarm alarm)
{ {
// 设置初始状态
alarm.AlarmStatus = AlarmStatus.Active; alarm.AlarmStatus = AlarmStatus.Active;
alarm.CreateTime = DateTime.Now; alarm.CreateTime = DateTime.Now;
alarm.UpdateTime = DateTime.Now; alarm.UpdateTime = DateTime.Now;
var createdAlarm = await _alarmRepository.AddAsync(alarm); var createdAlarm = await _alarmRepository.AddAsync(alarm);
// 发送告警通知
await _notificationService.SendAlarmNotificationAsync(createdAlarm); await _notificationService.SendAlarmNotificationAsync(createdAlarm);
return createdAlarm; return createdAlarm;
@ -93,7 +64,6 @@ namespace Haoliang.Core.Services
throw new KeyNotFoundException($"Alarm with ID {alarmId} not found"); throw new KeyNotFoundException($"Alarm with ID {alarmId} not found");
} }
// 更新字段
alarm.AlarmId = alarmId; alarm.AlarmId = alarmId;
alarm.UpdateTime = DateTime.Now; alarm.UpdateTime = DateTime.Now;
@ -185,464 +155,4 @@ namespace Haoliang.Core.Services
return await _alarmRepository.GetByDeviceAndDateRangeAsync(deviceId, startDate, endDate); return await _alarmRepository.GetByDeviceAndDateRangeAsync(deviceId, startDate, endDate);
} }
} }
public class AlarmRuleService : IAlarmRuleService
{
private readonly IAlarmRuleRepository _ruleRepository;
private readonly IAlarmRepository _alarmRepository;
private readonly IDeviceRepository _deviceRepository;
private readonly ILoggerService _logger;
public AlarmRuleService(
IAlarmRuleRepository ruleRepository,
IAlarmRepository alarmRepository,
IDeviceRepository deviceRepository,
ILoggerService logger)
{
_ruleRepository = ruleRepository;
_alarmRepository = alarmRepository;
_deviceRepository = deviceRepository;
_logger = logger;
}
public async Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule)
{
rule.IsActive = true;
rule.CreateTime = DateTime.Now;
rule.UpdateTime = DateTime.Now;
return await _ruleRepository.AddAsync(rule);
}
public async Task<AlarmRule> UpdateAlarmRuleAsync(int ruleId, AlarmRule rule)
{
var existingRule = await _ruleRepository.GetByIdAsync(ruleId);
if (existingRule == null)
{
throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");
}
rule.RuleId = ruleId;
rule.UpdateTime = DateTime.Now;
return await _ruleRepository.UpdateAsync(rule);
}
public async Task<bool> DeleteAlarmRuleAsync(int ruleId)
{
return await _ruleRepository.DeleteAsync(ruleId);
}
public async Task<AlarmRule> GetAlarmRuleByIdAsync(int ruleId)
{
return await _ruleRepository.GetByIdAsync(ruleId);
}
public async Task<IEnumerable<AlarmRule>> GetAllAlarmRulesAsync()
{
return await _ruleRepository.GetAllAsync();
}
public async Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync()
{
return await _ruleRepository.GetByStatusAsync(true);
}
public async Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId)
{
return await _ruleRepository.GetByDeviceIdAsync(deviceId);
}
public async Task<bool> EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
{
if (!rule.IsActive || status == null)
return false;
try
{
switch (rule.RuleType)
{
case AlarmRuleType.DeviceOffline:
return EvaluateDeviceOfflineRule(rule, status);
case AlarmRuleType.TemperatureHigh:
return EvaluateTemperatureRule(rule, status);
case AlarmRuleType.PressureHigh:
return EvaluatePressureRule(rule, status);
case AlarmRuleType.ProductionStop:
return EvaluateProductionStopRule(rule, status);
case AlarmRuleType.NetworkError:
return EvaluateNetworkErrorRule(rule, status);
default:
return false;
}
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to evaluate alarm rule {rule.RuleId}: {ex.Message}");
return false;
}
}
public async Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
{
var alarm = new Alarm
{
DeviceId = status.DeviceId,
DeviceCode = "", // Will be populated from device
AlarmType = rule.AlarmType,
Severity = rule.Severity,
Title = rule.AlarmTitle,
Description = rule.AlarmDescription,
AlarmStatus = AlarmStatus.Active,
RuleId = rule.RuleId,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now
};
// Get device code
var device = await _deviceRepository.GetByIdAsync(status.DeviceId);
if (device != null)
{
alarm.DeviceCode = device.DeviceCode;
}
return alarm;
}
public async Task TestAlarmRuleAsync(int ruleId)
{
var rule = await _ruleRepository.GetByIdAsync(ruleId);
if (rule == null)
throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");
// Get a sample device status for testing
var devices = await _deviceRepository.GetAllAsync();
if (!devices.Any())
throw new Exception("No devices available for testing");
var sampleDevice = devices.First();
var deviceStatus = new DeviceCurrentStatus
{
DeviceId = sampleDevice.Id,
Status = "Running",
IsRunning = true,
NCProgram = "O1234",
CumulativeCount = 1000,
RecordTime = DateTime.Now
};
// Evaluate the rule
var shouldTrigger = await EvaluateAlarmRuleAsync(rule, deviceStatus);
if (shouldTrigger)
{
var alarm = await GenerateAlarmFromRuleAsync(rule, deviceStatus);
alarm.Title = $"Test Alarm: {rule.AlarmTitle}";
alarm.Description = $"This is a test alarm for rule '{rule.RuleName}'.";
await _alarmRepository.AddAsync(alarm);
await _alarmRepository.SaveAsync();
await _logger.LogInformationAsync($"Test alarm created for rule {rule.RuleId}");
}
else
{
await _logger.LogInformationAsync($"Rule {rule.RuleId} did not trigger alarm during test");
}
}
private bool EvaluateDeviceOfflineRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check if device status indicates offline
return status.Status?.ToLower() == "offline" ||
!status.IsRunning ||
string.IsNullOrEmpty(status.NCProgram);
}
private bool EvaluateTemperatureRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Find temperature tag
var temperatureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("temp") == true || t.Id?.Contains("温度") == true);
if (temperatureTag == null || temperatureTag.Value == null)
return false;
if (decimal.TryParse(temperatureTag.Value.ToString(), out decimal temperature))
{
return temperature > rule.ThresholdValue;
}
return false;
}
private bool EvaluatePressureRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Find pressure tag
var pressureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("pressure") == true || t.Id?.Contains("压力") == true);
if (pressureTag == null || pressureTag.Value == null)
return false;
if (decimal.TryParse(pressureTag.Value.ToString(), out decimal pressure))
{
return pressure > rule.ThresholdValue;
}
return false;
}
private bool EvaluateProductionStopRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check if device has been stopped for specified duration
var stopDuration = TimeSpan.FromMinutes(rule.ThresholdValue);
return !status.IsRunning &&
status.RecordTime < DateTime.Now.Subtract(stopDuration);
}
private bool EvaluateNetworkErrorRule(AlarmRule rule, DeviceCurrentStatus status)
{
// Check for network-related errors in status
return status.Tags?.Any(t => t.Id?.Contains("error") == true && t.Value?.ToString() == "1") == true;
}
}
public class AlarmNotificationService : IAlarmNotificationService
{
private readonly IAlarmNotificationRepository _notificationRepository;
private readonly IEmailService _emailService;
private readonly ISmsService _smsService;
private readonly IWechatService _wechatService;
private readonly ILoggerService _logger;
private readonly IDeviceRepository _deviceRepository;
public AlarmNotificationService(
IAlarmNotificationRepository notificationRepository,
IEmailService emailService,
ISmsService smsService,
IWechatService wechatService,
ILoggerService logger,
IDeviceRepository deviceRepository)
{
_notificationRepository = notificationRepository;
_emailService = emailService;
_smsService = smsService;
_wechatService = wechatService;
_logger = logger;
_deviceRepository = deviceRepository;
}
public async Task SendAlarmNotificationAsync(Alarm alarm)
{
try
{
var device = await _deviceRepository.GetByIdAsync(alarm.DeviceId);
var notificationChannels = await GetNotificationChannelsForDevice(alarm.DeviceId);
foreach (var channel in notificationChannels)
{
if (channel.IsEnabled)
{
await SendNotificationViaChannel(alarm, channel, device);
}
}
// Log the notification
await LogNotificationSent(alarm, notificationChannels.Count());
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send alarm notification for alarm {alarm.AlarmId}: {ex.Message}");
}
}
public async Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms)
{
foreach (var alarm in alarms)
{
await SendAlarmNotificationAsync(alarm);
}
}
public async Task<bool> SendSmsNotificationAsync(string phoneNumber, string message)
{
try
{
return await _smsService.SendSmsAsync(phoneNumber, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send SMS to {phoneNumber}: {ex.Message}");
return false;
}
}
public async Task<bool> SendEmailNotificationAsync(string email, string subject, string message)
{
try
{
return await _emailService.SendEmailAsync(email, subject, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send email to {email}: {ex.Message}");
return false;
}
}
public async Task<bool> SendWechatNotificationAsync(string openId, string message)
{
try
{
return await _wechatService.SendMessageAsync(openId, message);
}
catch (Exception ex)
{
await _logger.LogErrorAsync($"Failed to send WeChat message to {openId}: {ex.Message}");
return false;
}
}
public async Task<IEnumerable<AlarmNotification>> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate)
{
return await _notificationRepository.GetByDateRangeAsync(startDate, endDate);
}
public async Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel)
{
// Validate channel configuration
if (!ValidateChannelConfiguration(channel))
return false;
// Save channel configuration
return await _notificationRepository.SaveChannelAsync(channel);
}
public async Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync()
{
return await _notificationRepository.GetAllChannelsAsync();
}
private async Task<List<NotificationChannel>> GetNotificationChannelsForDevice(int deviceId)
{
// This would typically query the database for device-specific notification settings
// For now, return a default set of channels
return new List<NotificationChannel>
{
new NotificationChannel { ChannelType = NotificationChannelType.Email, IsEnabled = true },
new NotificationChannel { ChannelType = NotificationChannelType.Sms, IsEnabled = false },
new NotificationChannel { ChannelType = NotificationChannelType.WeChat, IsEnabled = false }
};
}
private async Task SendNotificationViaChannel(Alarm alarm, NotificationChannel channel, Device device)
{
var message = FormatAlarmMessage(alarm, device);
var subject = $"Alarm: {alarm.AlarmType} - {device?.DeviceCode}";
switch (channel.ChannelType)
{
case NotificationChannelType.Email:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendEmailNotificationAsync(channel.Recipient, subject, message);
}
break;
case NotificationChannelType.Sms:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendSmsNotificationAsync(channel.Recipient, message);
}
break;
case NotificationChannelType.WeChat:
if (!string.IsNullOrEmpty(channel.Recipient))
{
await SendWechatNotificationAsync(channel.Recipient, message);
}
break;
}
}
private string FormatAlarmMessage(Alarm alarm, Device device)
{
return $"🚨 Alarm Alert\n\n" +
$"Device: {device?.DeviceCode} ({device?.DeviceName})\n" +
$"Type: {alarm.AlarmType}\n" +
$"Severity: {alarm.Severity}\n" +
$"Title: {alarm.Title}\n" +
$"Description: {alarm.Description}\n" +
$"Time: {alarm.CreateTime:yyyy-MM-dd HH:mm:ss}\n" +
$"Device ID: {alarm.DeviceId}";
}
private bool ValidateChannelConfiguration(NotificationChannel channel)
{
switch (channel.ChannelType)
{
case NotificationChannelType.Email:
return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.Contains("@");
case NotificationChannelType.Sms:
return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.All(char.IsDigit);
case NotificationChannelType.WeChat:
return !string.IsNullOrEmpty(channel.Recipient);
default:
return false;
}
}
private async Task LogNotificationSent(Alarm alarm, int channelCount)
{
var notification = new AlarmNotification
{
AlarmId = alarm.AlarmId,
NotificationTime = DateTime.Now,
ChannelsUsed = channelCount,
Success = true
};
await _notificationRepository.AddNotificationAsync(notification);
}
}
// Additional supporting classes and interfaces
public interface IEmailService
{
Task<bool> SendEmailAsync(string email, string subject, string message);
}
public interface ISmsService
{
Task<bool> SendSmsAsync(string phoneNumber, string message);
}
public interface IWechatService
{
Task<bool> SendMessageAsync(string openId, string message);
}
public interface IAlarmRuleRepository
{
Task<AlarmRule> AddAsync(AlarmRule rule);
Task<AlarmRule> UpdateAsync(AlarmRule rule);
Task<bool> DeleteAsync(int ruleId);
Task<AlarmRule> GetByIdAsync(int ruleId);
Task<IEnumerable<AlarmRule>> GetAllAsync();
Task<IEnumerable<AlarmRule>> GetByStatusAsync(bool isActive);
Task<IEnumerable<AlarmRule>> GetByDeviceIdAsync(int deviceId);
}
public interface IAlarmNotificationRepository
{
Task<AlarmNotification> AddNotificationAsync(AlarmNotification notification);
Task<IEnumerable<AlarmNotification>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
Task<bool> SaveChannelAsync(NotificationChannel channel);
Task<IEnumerable<NotificationChannel>> GetAllChannelsAsync();
}
} }

@ -5,9 +5,9 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Haoliang.Core.Services; using Haoliang.Core.Services;
using Haoliang.Models.Models.Device; using Haoliang.Models.Device;
using Haoliang.Models.Models.Production; using Haoliang.Models.Production;
using Haoliang.Models.Models.System; using Haoliang.Models.System;
namespace Haoliang.Core.Services namespace Haoliang.Core.Services
{ {

@ -6,8 +6,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Haoliang.Core.Services; using Haoliang.Core.Services;
using Haoliang.Models.Models.Device; using Haoliang.Models.Device;
using Haoliang.Models.Models.System; using Haoliang.Models.System;
using Haoliang.Models.Common; using Haoliang.Models.Common;
namespace Haoliang.Core.Services namespace Haoliang.Core.Services

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Haoliang.Models.Models.System; using Haoliang.Models.System;
using Haoliang.Models.Models.Production; using Haoliang.Models.Production;
namespace Haoliang.Core.Services namespace Haoliang.Core.Services
{ {

@ -5,10 +5,10 @@ using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Haoliang.Core.Services; using Haoliang.Core.Services;
using Haoliang.Data.Repositories; using Haoliang.Data.Repositories;
using Haoliang.Models.Models.Device; using Haoliang.Models.Device;
using Haoliang.Models.Models.Production; using Haoliang.Models.Production;
using Haoliang.Models.Models.System; using Haoliang.Models.System;
using Haoliang.Models.Models.DataCollection; using Haoliang.Models.DataCollection;
namespace Haoliang.Core.Services namespace Haoliang.Core.Services
{ {

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Haoliang.Models.Models.System; using Haoliang.Models.System;
namespace Haoliang.Core.Services namespace Haoliang.Core.Services
{ {

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Core")] [assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+c3d17cebb9da179f6753a56af8a0a77a244c32f3")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+816621dcb94c35c3cc1e4fd61efdefc7363e63f2")]
[assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Core")] [assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Core")] [assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

@ -1 +1 @@
8be02421dfff2584ed0de880e6906d7bb86a51af3956a22dc9c02300e5c63caa 7c8177bddf0522256331d06c7b8179260f0ae30b251ffa6343312621856d61d8

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Data")] [assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Data")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+c3d17cebb9da179f6753a56af8a0a77a244c32f3")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+816621dcb94c35c3cc1e4fd61efdefc7363e63f2")]
[assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Data")] [assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Data")]
[assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Data")] [assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Data")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

@ -1 +1 @@
74dde7117c2620296605ef8bcf766dedf67d1cb4aa2653155b7060e141ab9f7b 9e63ec6c034e84f83e590a9b38e0ea47d47fd346cebfe07ac47bd55fe9f8fef5

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Models")] [assembly: System.Reflection.AssemblyCompanyAttribute("Haoliang.Models")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+c3d17cebb9da179f6753a56af8a0a77a244c32f3")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+816621dcb94c35c3cc1e4fd61efdefc7363e63f2")]
[assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Models")] [assembly: System.Reflection.AssemblyProductAttribute("Haoliang.Models")]
[assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Models")] [assembly: System.Reflection.AssemblyTitleAttribute("Haoliang.Models")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

@ -1 +1 @@
2c18f2f48b9565bc973d3ca206e23b96d6b6815054341daa6858cdf703ae16bc 741778252b9e9c0c25248651ab3b55fec96b80773bde2b4133d7d29bdd8efb4d

Loading…
Cancel
Save