Как надежно сохранить ASP.NET IFRAME из события OnSave пользовательского объекта? - PullRequest
0 голосов
/ 10 апреля 2010

У меня есть собственное решение ASP.NET, развернутое в каталоге ISV приложения MS Dynamics CRM 4.0. Мы создали пользовательскую сущность, чей ввод данных требует большего динамизма, чем это возможно через конструктор форм в CRM. Для этого мы создали форму ASP.NET, отображаемую через IFRAME в главной форме объекта.

Вот как устроена функция сохранения:

  1. На странице имеется элемент управления ASP.NET, который сохраняет объект при нажатии. Эта кнопка скрыта CSS.
  2. Событие нажатия кнопки запускается из события JavaScript CRM OnSave.
  3. Событие запускается, и сущность сохраняется.

Вот вопросы:

  1. Когда пул приложений перерабатывается, первое сохранение (или несколько) может:
    1. не сохранить
    2. задерживается (т. Е. Интерфейс не показывает обновления, пока страница не будет обновлена ​​через несколько секунд)
  2. Сохранить и закрыть / Новое не может сохранить

Для выпусков 1.1 и 2, по-видимому, происходит то, что, хотя событие save запущено для пользовательской страницы ASP.NET, браузер перемещает / обновляет страницу, делая запрос на сервер недействительным. Это приводит к тому, что сохранение фактически не завершается.

Прямо сейчас это смягчается петлей задержки javascript для kludge на несколько секунд после вызова события сохранения кнопки внутри события OnSave объекта.

Есть ли способ заставить событие OnSave ожидать обратного вызова от IFRAME?

Ответы [ 4 ]

1 голос
/ 29 мая 2010

Решение, которое я реализовал (совсем недавно) для преодоления этой проблемы, немного сложно, но позвольте мне объяснить:

По существу - на странице с iFrame вы собираетесь отслеживать (в сеансе) событие сохранения и представлять результаты через WebMethod, который будет вызывать страница CRM (используя функциональность jquery .ajax ()) *

Лучший способ объяснить это с помощью примера кода (просто создайте новый проект веб-сайта с Default.aspx & IFramePage.aspx):

IFramePage.aspx ->

    <script type="text/javascript">

    SaveStuff = function() {            
        __doPostBack('SaveButton', '');
    }

</script>    
    Hello - I am an iFrame!<br />
    <asp:linkbutton id="SaveButton" runat="server" style="display:none;" onclick="SaveButton_Click" text="Save" />
    <asp:hiddenfield id="RandomGuidHiddenField" runat="server" />
</div>

IFramePage.aspx.cs ->

    public static object locker = new object();

/// <summary>
/// Gets the statuses.
/// </summary>
/// <value>The statuses.</value>
public static Dictionary<Guid, bool> Statuses
{
    get 
    {
        lock (locker)
        {
            if (HttpContext.Current.Session["RandomGuid"] == null)
            {
                HttpContext.Current.Session["RandomGuid"] = new Dictionary<Guid, bool>();
            }

            return (Dictionary<Guid, bool>) HttpContext.Current.Session["RandomGuid"];
        }
    }
}

[WebMethod]
public static bool CheckSaveComplete(string randomGuid)
{
    var currentGuid = new Guid(randomGuid);
    var originalTime = DateTime.Now;

    if (!Statuses.ContainsKey(currentGuid))
    {
        Statuses.Add(currentGuid, false);
    }

    while (!Statuses[currentGuid])
    {
        if (DateTime.Now.Subtract(originalTime) > new TimeSpan(0, 0, 0, 1))
        {
            return false;
        }

        Thread.Sleep(1000);
    }

    return true;
}

/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        this.RandomGuidHiddenField.Value = Guid.NewGuid().ToString();            
    }
}

/// <summary>
/// Handles the Click event of the SaveButton control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void SaveButton_Click(object sender, EventArgs e)
{
    var randomGuid = new Guid(this.RandomGuidHiddenField.Value);

    if (!Statuses.ContainsKey(randomGuid))
    {
        Statuses.Add(randomGuid, false);
    }

    Thread.Sleep(10000);

    Statuses[randomGuid] = true;
}

На моей странице Default.aspx (для имитации страницы сущности формы CRM) ->

   <script type="text/javascript">
    function OnSave() {
        var saveResult = false;
        var randomGuid = window.frames[$("#daIframe")[0].id].$("input[id$=RandomGuidHiddenField]").val();

        window.frames[$("#daIframe")[0].id].SaveStuff();


        $.ajax(
        {
            async: false,
            type: "POST",
            url: "IFramePage.aspx/CheckSaveComplete",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: '{"randomGuid" : "' + randomGuid + '"}',
            success: function(response) {
                if (response.d === true) {
                    alert(response.d);
                    saveResult = true;
                }
            }
        }
        );

    if (saveResult !== true) {
        alert("Oh No!");
    }
    else {
        alert("way to go!");
    }
}

</script>
<iframe name="daIframe" id="daIframe" src="IFramePage.aspx"></iframe>
<asp:textbox id="lsc_paymentinfo" runat="server" text="1000" /><br />
<input type="button" value="Save" onclick="OnSave();" />

Дайте мне знать, если у вас есть какие-либо вопросы!

1 голос
/ 11 апреля 2010

Мой предпочтительный метод обработки сохранения значений в iframe - через веб-сервис. Пусть форма CRM вызывает в вашем iframe функцию, которая собирает все поля и синхронно публикует их. Когда веб-служба возвращает ответ и возвращается функция сохранения, форма CRM выполнит ее сохранение.

Вот как может выглядеть ваш метод сохранения в iframe с использованием jQuery:

function save() {
    var saveResult = false;

    $.ajax({
        async: false,
        type: "POST",
        url: "/YourWebservice.asmx/SaveIframeValues",
        contentType: 'application/json; charset=utf-8',
        dataType: "json"
        data: '{ paramname : "paramvalue" }',
        success: function(response) {
            if (response.d === true) // assuming your webservice returns true upon success
            {
                saveResult = true;
            }
        }
    });

    if (saveResult !== true) {
        // alert user, perhaps

        // and stop the CRM form from saving
        event.returnValue = false;
        return false;
    } else {
        // iframe save was successful, time for a nap
    }
}
0 голосов
/ 11 апреля 2010

Одним из решений в этом случае является подключение состояния или событий IFrame и продолжение действия сохранения CRM только после перезагрузки IFrame после обратной передачи. Таким образом, если пользовательское приложение дает сбой или работает медленно, вы можете уведомить пользователя и отменить процесс сохранения.

0 голосов
/ 10 апреля 2010

Одна вещь, которая может помочь, - увеличить время ожидания пула приложений в IIS. По умолчанию его значение равно 20 минутам, поэтому, если никто не использует ваш IFrame в течение 20 минут, он будет перезагружать пул приложений и приведет к большой задержке при следующем запуске.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...