C# HttpClient null при втором запуске - PullRequest
0 голосов
/ 11 января 2020

У меня проблема. Я создал следующую ViewModel:

public class TemplateListViewModel
{
    public double WidthHeight { get; set; }

    public ICommand LoadTemplates => new Command(MyHandler);
    public int CurrentTemplateCountReceived;
    public bool HitBottomOfList = false;
    public ObservableCollection<TemplateSource> sourceList { get; set; }


    public TemplateListViewModel()
    {
        CurrentTemplateCountReceived = 0;
        sourceList = new ObservableCollection<TemplateSource>();

        var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
        var width = mainDisplayInfo.Width;
        var density = mainDisplayInfo.Density;
        var ScaledWidth = width / density;

        WidthHeight = (ScaledWidth / 2);

        loadingTemplates += onLoadingTemplates;
        LoadTemplateList();
    }

    private event EventHandler loadingTemplates = delegate { };

    private Task LoadTemplateList()
    {
        loadingTemplates(this, EventArgs.Empty);
        return null;
    }

    private async void onLoadingTemplates(object sender, EventArgs args)
    {
        if (HitBottomOfList == false)
        {
            List<Template> templateList = await App.RestService.GetTemplates(App.User, CurrentTemplateCountReceived);

            if (templateList != null)
            {
                foreach (var template in templateList)
                {
                    ImageSource source = ImageSource.FromUri(new Uri("http://alexander.vreeswijk.eu/memento/" + App.TemplateSource + template.FileName));
                    TemplateSource templateSource = new TemplateSource { Id = template.Id, Source = source, WidthHeight = WidthHeight, FileName = template.FileName };
                    sourceList.Add(templateSource);
                }

                CurrentTemplateCountReceived = sourceList.Count;
            }
            else
            {
                HitBottomOfList = true;
            }
        }
    }

    bool handling = false;

    public async void MyHandler()
    {
        // already handling an event, ignore the new one
        if (handling) return;

        handling = true;

        await LoadTemplateList();

        handling = false;
    }
}

А вот RestService.cs:

HttpClient client;
public string ErrorMessage { get; set; }

public RestService()
{
    client = new HttpClient();
    client.MaxResponseContentBufferSize = 256000;
    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
}

public async Task<List<Template>> GetTemplates(User user, int offset)
{
    var postData = new List<KeyValuePair<string, string>>();
    postData.Add(new KeyValuePair<string, string>("un", user.Username));
    postData.Add(new KeyValuePair<string, string>("pw", user.Password));
    postData.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
    var content = new FormUrlEncodedContent(postData);
    var weburl = "mysite.org/myapp/get_templates.php";
    List<Template> response = await PostResponseTemplates(weburl, content);

    return response;
}

public async Task<List<Template>> PostResponseTemplates(string weburl, FormUrlEncodedContent content)
{
    var response = await client.PostAsync(weburl, content);
    var json = await response.Content.ReadAsStringAsync();

    if (json != "Nothing")
    {
        var jObject = JObject.Parse(json);
        var templatePropery = jObject["Templates"] as JArray;
        List<Template> templateList = new List<Template>();

        foreach (var property in templatePropery)
        {
            List<Template> propertyList = new List<Template>();
            propertyList = JsonConvert.DeserializeObject<List<Template>>(property.ToString());
            templateList.AddRange(propertyList);
        }

        var sourcePropery = (JObject)jObject["Source"];
        foreach (var property in sourcePropery)
        {
            string tempplateSource = property.Value.Value<string>();
            App.TemplateSource = tempplateSource;
        }

        return templateList;
    }
    else
    {
        ErrorMessage = json;
        return default(List<Template>);
    }
}

ICommand LoadTemplates => new Command(MyHandler); вызывается, когда CollectionView почти достигает дна список, чтобы было больше данных. Затем я создал MyHandler, чтобы проверить, есть ли уже событие, занятое веб-вызовом, чтобы получить больше данных, потому что оно запускает событие несколько раз. Наконец, он выполняет onLoadingTemplates, который получает данные с моей веб-страницы.

Теперь при первом запуске с LoadTemplateList(); в конструкторе все работает отлично, но когда он выполняет его, как: await LoadTemplateList();, когда событие инициируется, происходит сбой в следующей строке в RestService.cs: var response = await client.PostAsync(weburl, content); с ошибкой:

'Ссылка на объект не установлена ​​на экземпляр объекта.'

Может кто-нибудь сказать мне, почему это происходит, когда он получает данные, когда событие инициируется?

Ответы [ 2 ]

0 голосов
/ 12 января 2020

Выполняя здесь детективную работу.

Поскольку вы сказали, что получаете NullReferenceException

Ссылка на объект не установлена ​​на экземпляр объекта.

в строке

var response = await client.PostAsync(weburl, content);

, где ни weburl, ни content не могут быть нулевыми, поскольку были созданы ранее в методе GetTemplates, остается только вероятность того, что client null в предыдущей строке: если это так, убедитесь, что вы устанавливаете следующие свойства в своем клиенте после его создания:

httpClient.DefaultRequestHeaders.ConnectionClose = false;
HttpWebRequest.KeepAlive = true;

Есть хорошая запись в HttpClient BestPractices в документах MSFT.

Надеюсь, это поможет!

0 голосов
/ 11 января 2020

Я бы рискнул сделать ставку на текущую ошибку CollectionView.

Это не «вызываемый второй раз» случай, а средство визуализации просто падает, когда вы изменяете уже загруженную границу ObservableCollection (а окно с CollectionView скрыто).

Сначала я подумал, что где-то в рендере он выполняется в вызывающем потоке, не являющемся пользовательским интерфейсом. Но даже когда вы пытаетесь изменить связанный ObservableCollection из UI-потока, рендерер все равно падает.

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

...