.NET Core 2 MVC - 存储GET方法的对象

3
我在主页上有一个搜索表单,可以搜索外部数据库中的可用房间和酒店。提交表单后,用户将被重定向到一个新页面,显示可用酒店的列表(房间稍后会出现)。
提交表单后,搜索参数被放入一个字符串中,然后通过ModelManager传递给TcpConnectionManager类,该字符串被序列化为json并通过socket发送到外部Java服务器。服务器反序列化json,将字符串元素放入SQL查询中,然后检查数据库并返回所有可用酒店对象。这些酒店对象随后被放置在HotelList对象中,序列化为json并通过socket发送回TcpConnectionManager类。
我的最大问题是在HotelController中实现GET方法。尝试将HotelList对象存储在TcpConnectionManager类中,但GET方法总是返回null对象。
到目前为止我已经通过实现一个单例类TempHotelsStorage来达到想要的效果,该类具有存储和检索HotelList对象的方法,但我的最大关切是这是否是在这种情况下一个好的/正确的方法?如果不是,如何改进?
HomeController.cs :
namespace NETCoreWebApp.Controllers
{
public class HomeController : Controller
{
    private readonly IModelManager iModelManager = new ModelManager();

    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Hotel()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Index(SearchRoomsModel model)
    {
        string query = string.Format("{0},{1} 12:00,{2} 12:00,{3},{4}", model.Location, model.CheckIn, model.CheckOut, model.NumAdults, model.NumChild);

        iModelManager.GetAvailableRooms(query);

        return RedirectToAction("Hotel");
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}
}

HotelController.cs:

namespace NETCoreWebApp.Controllers
{
[Route("api/hotel")]
[ApiController]
public class HotelController : Controller
{
    public TempHotelsStorage hotelsStorage = TempHotelsStorage.Instance;

    [HttpGet]
    public ActionResult<HotelList> Get()
    {            
        return hotelsStorage.GetHotelsFromStorage(); 
    }
}
}

TcpConnectionManager.cs :
public class TcpConnectionManager
{
    public TempHotelsStorage hotelStorage = TempHotelsStorage.Instance;

    public void GetAvailableRooms(string query)
    {
        //Sending json to other server

        TcpClient clientSocket = new TcpClient();

        clientSocket.Connect("127.0.0.1", 6767);

        NetworkStream ns = clientSocket.GetStream();

        string jsonRequest = query;

        string jsonToSend = JsonConvert.SerializeObject(jsonRequest);

        byte[] dataBytes = Encoding.UTF8.GetBytes(jsonToSend);

        ns.Write(dataBytes, 0, dataBytes.Length);

        //Receiving json from other server

        byte[] buffer = new byte[clientSocket.ReceiveBufferSize];

        int bytesRead = ns.Read(buffer, 0, clientSocket.ReceiveBufferSize);

        string DataReceived = Encoding.UTF8.GetString(buffer, 2, bytesRead);

        HotelList hotelList = JsonConvert.DeserializeObject<HotelList>(DataReceived);

        hotelStorage.SaveHotels(hotelList);

        clientSocket.Close();
        ns.Close();
    }
}

TempHotelsStorage.cs :

namespace NETCoreWebApp.Models
{
public class TempHotelsStorage
{
    private static readonly TempHotelsStorage instance = new TempHotelsStorage();

    static TempHotelsStorage() { }
    private TempHotelsStorage() { }

    public HotelList hotelList { get; set; } = new HotelList();

    public void SaveHotels(HotelList hList)
    {
        for (int i = 0; i < hList.Size(); i++)
        {
            hotelList.AddHotel(hList.GetHotelByIndex(i));
        }
    }

    public HotelList GetHotelsFromStorage()
    {
        return hotelList;
    }

    public static TempHotelsStorage Instance
    {
        get
        {
            return instance;
        }
    }
}
}

使用jQuery列出所有酒店:

function getData() {
$.ajax({
    type: "GET",
    url: uri,
    cache: false,
    dataType: 'json',
    success: function (data) {

        const hotelListContainer = $('#hotelListContainer');          

        for (var i = 0; i < data.hotelList.length; i++)
        {
            hotelListContainer
                .append(
                    "<div class='col-md-12' id='hotelListItem'>" +
                    "<div class='col-md-3' id='hotelItemPicture'>ID:" + data.hotelList[i].hid + "</div>" +
                    "<div class='col-md-9' id='hotelItemDescription'>NAME:" + data.hotelList[i].name + "</div>" +
                    "</div>"
                );
        }
    }
});
}

HTML标记:

<div class="container-fluid" id="hotelListArea">
<div class="row">
    <div class="col-md-2"></div>
    <div class="col-md-8" id="centerHotelListArea">            
        <div id="hotelListContainer">
            <div id="hotelContainerItem"></div>
        </div>
    </div>
    <div class="col-md-2"></div>
</div>


使用您的方法,搜索结果(包含可用酒店列表的页面)将返回应用程序生命周期内加载的所有酒店。 - Fabio
@Fabio 不确定我是否理解了你的意思。你能否详细说明一下? - RollerMobster
1
TempHotelsStoragehotelList 将包含应用程序生命周期中由不同用户发现的所有酒店,因为 TempHotelsStorage 是单例。如果用户经常搜索酒店,则您的应用程序可能会耗尽内存。 - Fabio
@Fabio 感谢您的澄清。您对如何更好地完成此任务有什么建议吗? - RollerMobster
1
为什么您不能使 TcpConnectionManager.GetAvailableRooms 返回找到的酒店,然后将其传递给显示搜索结果的视图? - Fabio
@Fabio的GetAvailableRooms()方法返回HotelList对象给Home控制器的POST方法,我该如何将这个对象传递给Hotel控制器的GET方法? - RollerMobster
2个回答

3
您可以通过依赖注入来处理服务的生命周期,这样可以减少麻烦。您可以在Startup类的ConfigureServices方法中注册服务,声明其接口和实现,例如:
services.AddTransient<ITcpConnectionManager, TcpConnectionManager>();
然后将该服务作为控制器的构造函数参数添加即可。
此外,您的TempHotelsStorage类似乎有些多余。如果您只是在GetAvailableRooms方法中返回JsonConvert.DeserializeObject<HotelList>(DataReceived);,就可以避免使用它。
通常情况下,单例对象用于需要在应用程序的整个生命周期中保留对象的情况,例如保留某些状态。但在这里不需要这样做。

0
根据Marchyello的建议,我使用依赖注入首先在Startup类中注册了单例服务:
services.AddSingleton<IModelManager, ModelManager>();

然后将单例服务作为构造函数参数添加到每个控制器中,就像这样:

    private readonly IModelManager _modelManager;

    public HotelController(IModelManager modelManager)
    {
        _modelManager = modelManager;
    }

ModelManager类是一个简单的门面,作为API控制器存储和检索数据的访问点,通过调用GET和POST方法。
HomeController:
    [HttpPost]
    public IActionResult Index(SearchRoomsModel model)
    {
        string _query = string.Format("{0},{1} 12:00,{2} 12:00,{3},{4}", model.Location, model.CheckIn, model.CheckOut, model.NumAdults, model.NumChild);

        _modelManager.SaveQuery(_query);

        return RedirectToAction("Hotel");
    }

酒店控制器:

    [HttpGet]
    public ActionResult<HotelList> Get()
    {
        return _modelManager.ReturnQuery();
    }

模型管理器:

    private readonly TcpConnectionManager _tcpManager = new TcpConnectionManager();
    public string _query;

    public void SaveQuery(string query)
    {
        _query = query;
    }

    public HotelList ReturnQuery()
    {
        HotelList hotelList = _tcpManager.ReturnHotelList(_query);

        return hotelList;
    }

ModelManager是一个单例,因为酒店控制器需要访问与Home控制器存储查询字符串相同的ModelManager实例,然后重定向到Hotel视图。此外,下一步将基于酒店选择列出可用房间,Room控制器的GET方法将需要访问与Hotel控制器相同的HotelList对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接