Представление существует в ASP.NET MVC?

Мне потребовалось время, чтобы рассмотреть все возможные решения, хотя их было совсем немного.

  1. Здесь я нашел что-то похожее на мою проблему. Сделал адаптацию кода, предоставленного там ... Хорошо, просто взял большую часть этого ответа =)
  2. @ Комментарий GM подтолкнул меня к мысли, что сокет api в этом случае должен отличаться только headers

Руководства сказали мне, что флаг SO_LINGER часто является результатом плохой архитектуры (в большинстве случаев клиент должен закрывать соединение, а не сервер), после нескольких экспериментов он получил этот флаг В моем случае это было бесполезно.

Привязка к точному IP приводит к нескольким сложностям, скорее костыль, чем решение ИМХО.

Итак, после незначительной адаптации класс прослушивания сокетов стал примерно таким:

QTcpServer2.h

#pragma once

#include 
#include 

class QTcpServer2 : public QTcpServer
{
  QMutex            mConnectionMutex;
  QList    mSocketDescriptors;
  const int         mPort;
  bool              mConnectionSuccessful;

private:
  /*override */virtual void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

public:
  bool TakeIncomingSocketDescription(qintptr& socketDescriptor);

  bool isConnectionSuccessfull() const
  { return mConnectionSuccessful; }

public:
  QTcpServer2(int port);
};

QTcpServer.cpp

#include "QTcpServer2.h"

#include 

#ifdef Q_OS_WIN
    #include 
    #pragma comment(lib, "ws2_32.lib")
#endif

#ifdef Q_OS_LINUX
    #include 
    #include 
    #include 
#endif

void QTcpServer2::incomingConnection(qintptr socketDescriptor)
{
    QMutexLocker lock(&mConnectionMutex);
    mSocketDescriptors.append(socketDescriptor);
}

bool QTcpServer2::TakeIncomingSocketDescription(qintptr& socketDescriptor)
{
    QMutexLocker lock(&mConnectionMutex);
    if (mSocketDescriptors.empty()) {
        return false;
    }
    socketDescriptor = mSocketDescriptors.takeFirst();
    return true;
}

QTcpServer2::QTcpServer2(int port)
    : QTcpServer()
    , mPort(port)
    , mConnectionSuccessful(false)
{
    // open server and listen on given port
    int sockfd = 0;
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));

    sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        qDedug() << "QTcpServer2: socket couldn't be opened successfully!";
        return; //RET
    }

#ifdef Q_OS_WIN
    // Not required in Linux, won't make any good 
    int flag = 1;
    if(::setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&flag), sizeof(int)) < 0)
    {
        qDedug() << "QTcpServer2: Can't set SO_REUSEADDR";
        return; //RET
    }
#endif

    //set Address,IFace, Port...
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(static_cast(mPort));


    if (::bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(sockaddr_in)) < 0)
    {
        qDedug() << "QTcpServer2: can't bind socket" ;
        return; //RET
    }

    if(::listen(sockfd, SOMAXCONN) < 0)
    {
        qDedug() << "QTcpServer2: can't listen on port";
        return; //RET
    }

    //forward our descriptor with SO_REUSEPORT to QTcpServer member
    setSocketDescriptor(sockfd);
    mConnectionSuccessful = true;
    qDedug() << "QTcpServer2: socket success =)";
}

Поскольку «магическая проблема с сокетами» появилась только в Windows 8.1, #define делает SO_REUSEADDR используемым только в Windows. В Linux Qt уже устанавливает этот флаг самостоятельно (как показано в вопросе), поэтому этот небольшой патч только улучшил поведение Windows, чтобы соответствовать желаемому, предоставленному в Linux без проблем.

Надеюсь, ничего подобного никогда не понадобится на других платформах.

93
задан Peter Mortensen 6 October 2018 в 07:29
поделиться

4 ответа

 private bool ViewExists(string name)
 {
     ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, name, null);
     return (result.View != null);
 }

Для тех, кто ищет метод расширения копирования / вставки:

public static class ControllerExtensions
{
    public static bool ViewExists(this Controller controller, string name)
    {
        ViewEngineResult result = ViewEngines.Engines.FindView(controller.ControllerContext, name, null);
        return (result.View != null);
    }
}
149
ответ дан 24 November 2019 в 06:17
поделиться

В ядре asp.net 2.x ViewEngines свойство больше не существует так, мы должны использовать ICompositeViewEngine сервис. Это вариант принятого ответа с помощью внедрения зависимости:

public class DemoController : Controller
{
    private readonly IViewEngine _viewEngine;

    public DemoController(ICompositeViewEngine viewEngine)
    {
        _viewEngine = viewEngine;
    }

    private bool ViewExists(string name)
    {
        ViewEngineResult viewEngineResult = _viewEngine.FindView(ControllerContext, name, true);
        return viewEngineResult?.View != null;
    }

    public ActionResult Index() ...
}

Для любопытного: основной интерфейс IViewEngine не регистрируется как услуга, таким образом, мы должны ввести ICompositeViewEngine вместо этого. FindView() метод однако предоставлен IViewEngine, таким образом, членская переменная может использовать основной интерфейс.

0
ответ дан 24 November 2019 в 06:17
поделиться

Если вы хотите повторно использовать это в нескольких действиях контроллера, основываясь на решении, данном Дэйвом, вы можете определить результат пользовательского представления следующим образом:

public class CustomViewResult : ViewResult
{
    protected override ViewEngineResult FindView(ControllerContext context)
    {
        string name = SomeMethodToGetViewName();

        ViewEngineResult result = ViewEngines.Engines.FindView(context, name, null);

        if (result.View != null)
        {
            return result;
        }

        return base.FindView(context);
    }

    ...
}

Затем в вашем действии просто верните экземпляр вашего настраиваемого представления:

public ActionResult Index()
{ 
    return new CustomViewResult();
}
2
ответ дан 24 November 2019 в 06:17
поделиться

А как насчет того, чтобы попробовать что-то вроде следующего, предполагая, что вы используете только один движок представления:

bool viewExists = ViewEngines.Engines[0].FindView(ControllerContext, "ViewName", "MasterName", false) != null;
18
ответ дан 24 November 2019 в 06:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: