How to call HTTClient API call using iOS background session?
I have a requirement to create a background Task to fetch API calls, using Xamarin.iOS. The API calls are fetched using NSUrlSession CreateDownloadTask
, was able to fetch the API contents without any issues. But app's legacy API code was written using HTTPClient library & when calling HTTPClient GetAsync
methods and moving the app to the background is causing this error
NSURLErrorDomain - Lost connection to background transfer service.
Following is the code used to create HTTPClient background service
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration(BackgroundSessionId);
configuration.HttpMaximumConnectionsPerHost = 6;
configuration.NetworkServiceType = NSUrlRequestNetworkServiceType.Background;
configuration.AllowsCellularAccess = true;
configuration.WaitsForConnectivity = true;
configuration.AllowsConstrainedNetworkAccess = true;
configuration.AllowsExpensiveNetworkAccess = true;
configuration.ShouldUseExtendedBackgroundIdleMode = true;
configuration.TimeoutIntervalForRequest = 600.0;
configuration.TimeoutIntervalForResource = 1200.0;
var handler = new NSUrlSessionHandler(configuration);
var httpClient = new HttpClient(handler);
var response = await httpClient.GetAsync(APIURL_DOWNLOAD);
using (var content = response.Content)
{
var result = await content.ReadAsStringAsync();
Console.WriteLine(result);
}
I Would like to know a workaround to achieve HTTPClient calls in the background.
Thanks in advance
do you know?
how many words do you know
See also questions close to this topic
-
C# - Adding condition to func results in stack overflow exception
I have a func as part of specification class which sorts the given iqueryable
Func<IQueryable<T>, IOrderedQueryable<T>>? Sort { get; set; }
When i add more than one condition to the func like below , it results in stack overflow exception.
spec.OrderBy(sc => sc.Case.EndTime).OrderBy(sc => sc.Case.StartTime);
The OrderBy method is implemented like this
public ISpecification<T> OrderBy<TProperty>(Expression<Func<T, TProperty>> property) { _ = Sort == null ? Sort = items => items.OrderBy(property) : Sort = items => Sort(items).ThenBy(property); return this; }
Chaining or using separate lines doesn't make a difference.
This problem gets resolved if I assign a new instance of the specification and set it's func, but i don't want to be assigning to a new instance everytime. Please suggest what am i missing here and how to reuse the same instance (if possible).
-
How to projection fields for a dictionary (C#, MongdoDB)
I am trying my luck here, I have a model which is like the following
public class RowData : BaseBsonDefinition { . [BsonExtraElements] [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)] public Dictionary<string, object> Rows { get; set; } = new(StringComparer.OrdinalIgnoreCase); . }
In result, the schema in the MongoDB looks like
{ "_id": { "$binary": { "base64": "HiuI1sgyT0OZmcgGUit2dw==", "subType": "03" } }, "c1": "AAA", "c8": "Fully Vac", "c10": "", }
Those c1, c8 and c10 fields are keys from the dictionary, my question is how to dynamic project those fields?
I tried
Builders<RowData>.Projection.Exclude(p => "c1")
It seems the MongoDB driver can not handle a value directly.
Anyone could point me in the correct direction?
Thanks,
-
How do I add new DataSource to an already Databinded CheckBoxList
i'm building a web form that show Database's item(Tables, Rows, FK,...)
I have a CheckBoxList of Tables (
chkListTable
) which will show a new CheckBoxList of Rows (chkListRow
) everytime I SelectedIndexChanged fromchkListTable
. The problem is i can show the items fromchkListTable
with 1 selected item. But i don't know how to showchkListRow
if multiple item fromchkListTable
are selected.Here are my codes:
aspx
:<div> <asp:Label ID="Label2" runat="server" Text="Table: "></asp:Label> <asp:CheckBoxList ID="chkListTable" runat="server" DataTextField="name" DataValueFeild="name" AutoPostBack="true" OnSelectedIndexChanged="chkListTable_SelectedIndexChanged"> </asp:CheckBoxList> </div> <div> <asp:CheckBoxList ID="chkListRow" runat="server" DataTextField="COLUMN_NAME" DataValueField="COLUMN_NAME" RepeatDirection="Horizontal"> </asp:CheckBoxList> </div>
aspx.cs
:protected void chkListTable_SelectedIndexChanged(object sender, EventArgs e) { tableName.Clear(); foreach (ListItem item in chkListTable.Items) { if(item.Selected) { tableName.Add(item.Text.Trim()); } } for(int i = 0; i < tableName.Count; i++) { String query = "USE " + dbname + " SELECT * FROM information_schema.columns" + " WHERE table_name = '" + tableName[i] + "'" + " AND COLUMN_NAME != 'rowguid'"; chkListRow.DataSource = Program.ExecSqlDataReader(query); chkListRow.DataBind(); Program.conn.Close(); } }
Program.cs
:public static bool Connect() { if (Program.conn != null && Program.conn.State == ConnectionState.Open) Program.conn.Close(); try { Program.conn.ConnectionString = Program.constr; Program.conn.Open(); return true; } catch (Exception e) { return false; } } public static SqlDataReader ExecSqlDataReader(String query) { SqlDataReader myreader; SqlCommand sqlcmd = new SqlCommand(query, Program.conn); sqlcmd.CommandType = CommandType.Text; if (Program.conn.State == ConnectionState.Closed) Program.conn.Open(); try { myreader = sqlcmd.ExecuteReader(); return myreader; myreader.Close(); } catch (SqlException ex) { Program.conn.Close(); return null; } }
I want my display to be like this:
[x]Table1 [x]Table2 [ ]Table3 [ ]Row1(Table1) [ ]Row2(Table1) [ ]Row3(Table1) [ ]Row1(Table2) [ ]Row2(Table2)
-
Xamarin MAUI application not shows correct output
I have downloaded Visual Studio 2022 Professional (preview) version from MS Document. Also I have followed the other steps to create first sample application using .Net MAUI template after VS installed.
It does create new project with all the required dependency. I have installed Android sdk api v30 and created a simulator as mentioned in the official document.
When I have run the application on Android Emulator it does take a lot time to run and after it loaded properly it shows wrong output. It's just showing two Hello World label, while MainPage.xaml does have button as well but that button is not displayed. I have attached output screenshot here:
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiApp1.MainPage"> <ScrollView> <VerticalStackLayout Spacing="25" Padding="30"> <Label Text="Hello, World!" SemanticProperties.HeadingLevel="Level1" FontSize="32" HorizontalOptions="Center" /> <Label Text="Welcome to .NET Multi-platform App UI" SemanticProperties.HeadingLevel="Level1" SemanticProperties.Description="Welcome to dot net Multi platform App U I" FontSize="18" HorizontalOptions="Center" /> <Label Text="Current count: 0" FontSize="18" FontAttributes="Bold" x:Name="CounterLabel" HorizontalOptions="Center" /> <Button Text="Click me" FontAttributes="Bold" SemanticProperties.Hint="Counts the number of times you click" Clicked="OnCounterClicked" HorizontalOptions="Center" BackgroundColor="Orange" TextColor="White"/> <Image Source="dotnet_bot.png" SemanticProperties.Description="Cute dot net bot waving hi to you!" WidthRequest="250" HeightRequest="310" HorizontalOptions="Center" /> </VerticalStackLayout> </ScrollView> </ContentPage>
Does anyone know what is wrong here in the app? I have followed the steps mentioned in the MS Document which I have mentioned in the question.
- Change main page of TabbedPage, Xamarin.iOS
-
How to get selected item in Xamarin
I have a Picker in Xamarin and I want to pass the selected item in Picker to the another page(TablePage). Below this Picker there is a button and whenever it is clicked I want to go to the other page and display the selected value in the pther page.
<Picker x:Name="SelectTablePicker" Title="Select table" TextColor="#676FA3" TitleColor="#676FA3" FontSize="Title" ItemsSource="{Binding TablesFromViewModelCollector}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedTable}" /> <Button x:Name="SelectTableButton" Text="Select Table" HorizontalOptions="Center" Style="{DynamicResource TitleStyle}" Clicked="Selected_Button" />
So how I am trying to pass this value is with click event:
async void Selected_Button(object sender, System.EventArgs e) { var SelectTablePicker = (Picker)sender; int selectedIndex = SelectTablePicker.SelectedIndex; if (selectedIndex != -1) { await Navigation.PushAsync(new TablePage((string)SelectTablePicker.ItemsSource[selectedIndex])); } }
And on the Table Page, I created Label where I want to show the selected item:
<Label x:Name="MyLabel" Text="#" HorizontalOptions="Fill" Grid.Column="0" BackgroundColor="#FF5959" TextColor="#EEF2FF" HorizontalTextAlignment="Left" Padding="0, 0, 0, 10" VerticalTextAlignment="Center"/>
And here its controller:
public TablePage(string tableName) { InitializeComponent(); MyLabel.Text = $"{UserName}"; }
But whenever I click the button I am getting an error and I couldnt figure out why.
-
What's the correct way to send PARAMS when using HttpClient.SendAsync()?
I have an application that is using a remote API. That API requires that I send PARAMS before it will accept the request as valid. Currently I send
x-www-form-urlencoded
values through theBody
of the API call.I want to NOT send it in the
Body
and instead send it asParams
. I was just going to add it to the end of the URL to "fix it" and move on but, I feel like the is a better way to go about it maybe? Something that accounts for converting all the special characters to URL friendly characters (like the@
character to%40
).Is there a proper way of adding the params to the request or do you just toss them on to the end of the Request URL (URL Endpoint)?
-
void function and async tasks not working propperly?
Im taking 2 inputs from the ui, parsing them to be format compatible with an external api, in my function i call a task for get the autentication token(in this api all request must have the aut token, except the one who gets the token), i save the token in an object. I begin other task if the first one is ok, with the new header and parameters, i make the request and its all ok
My problem: In the VS Enviroment(ISS in localhost used with chrome) its all ok, its works perfectly, but when i publish it, in my site isn't working propperly, in fact the output i get is this line "showError("Error de conexión en autenticación");" Like the first task have an exception or something, i tried everything, my code maybe isn't perfect, but it`s quite standard tho. "showError()" is a function that just open a pop-up with the message in the "". All my objects are initialized in the page_load.
Any recommendation for synthesize or fixing my code is well received.
PD: Sorry for my bad english.
public static HttpClient clientcred = null; protected void txtCCredencial_TextChanged(object sender, EventArgs e) { ApiCredencial cred = SessionData.apiCredencial; cred.CodigoValido = false; if (!String.IsNullOrEmpty(txtAfiliado.Text) && !String.IsNullOrEmpty(txtCCredencial.Text)) { CredencialDigital(); } else { showError("Debe ingresar un número de afiliado previamente"); } } protected void CredencialDigital() { ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls12; ApiCredencial cred = SessionData.apiCredencial; AutenticacionCredencial autCred = SessionData.autCredencial; RespuestaCredencial dataCred = SessionData.dataCredencial; cred.folderCredencial = txtAfiliado.Text.Insert(6, "-"); cred.codeCredencial = txtCCredencial.Text; try { autCred = CredAsync().ConfigureAwait(true).GetAwaiter().GetResult(); } catch (Exception ex) { autCred = null; showError("Error de conexión en autenticación"); } if (autCred != null) { try { dataCred = ResCredAsync().ConfigureAwait(true).GetAwaiter().GetResult(); } catch (Exception ex) { dataCred = null; showError("Código inválido, intente nuevamente"); } if (dataCred != null) { if (Convert.ToString(dataCred.status) == "VALID_CODE") { cred.CodigoValido = true; } else if (Convert.ToString(dataCred.status) == "INVALID_CODE") { showError("Código inválido, intente nuevamente"); } else { showError("Pasó algo inesperado, intente nuevamente"); } } } } protected async Task<AutenticacionCredencial> CredAsync() { ApiCredencial cred = SessionData.apiCredencial; AutenticacionCredencial autCred = SessionData.autCredencial; clientcred = new HttpClient(); clientcred.BaseAddress = new Uri(@"https://xxxx.xxxx.com.ar/oauth/token"); clientcred.DefaultRequestHeaders.Accept.Clear(); clientcred.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var KeysAPISAMI = new Dictionary<string, string> { {"grant_type" , "authorization_api_key"}, {"account_key" , "xxxxxxxx"}, {"account_secret" , "xxxxxxxx"} }; var respautCredencial = await clientcred.PostAsync(clientcred.BaseAddress, KeysAPISAMI, new JsonMediaTypeFormatter()).ConfigureAwait(false); respautCredencial.EnsureSuccessStatusCode(); if (respautCredencial.IsSuccessStatusCode) { autCred = await respautCredencial.Content.ReadAsAsync<AutenticacionCredencial>().ConfigureAwait(false); cred.tokenCredencial = autCred.access_token; } else showError("Error, autenticación incorrecta, intente nuevamente"); clientcred.Dispose(); return autCred; } protected async Task<RespuestaCredencial> ResCredAsync() { ApiCredencial cred = SessionData.apiCredencial; RespuestaCredencial dataCred = SessionData.dataCredencial; clientcred = new HttpClient(); clientcred.BaseAddress = new Uri(@"https://xxxx.xxxx.com.ar/affiliates/validate"); clientcred.DefaultRequestHeaders.Accept.Clear(); clientcred.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); clientcred.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cred.tokenCredencial); var ValoresCredencial = new Dictionary<string, string> { { "folder" , cred.folderCredencial }, { "code" , cred.codeCredencial } }; var respCredencial = await clientcred.PostAsync(clientcred.BaseAddress, ValoresCredencial, new JsonMediaTypeFormatter()).ConfigureAwait(false); respCredencial.EnsureSuccessStatusCode(); if (respCredencial.IsSuccessStatusCode) { dataCred = await respCredencial.Content.ReadAsAsync<RespuestaCredencial>().ConfigureAwait(false); } else showError("Error, intente nuevamente"); clientcred.Dispose(); return dataCred; }``` My objects are: public class ApiCredencial { public string folderCredencial { get; set; } public string codeCredencial { get; set; } public string tokenCredencial { get; set; } public bool CodigoValido { get; set; } = false; } public class Document { public string type { get; set; } public string number { get; set; } } public class Code { public List<int> seeds { get; set; } public List<int> modifiers { get; set; } } public class DatosAfiliadoCredencial { public string id { get; set; } public string family_group { get; set; } public string status { get; set; } public string folder { get; set; } public string name { get; set; } public string lastname { get; set; } public Document document { get; set; } public string email { get; set; } public string plan_name { get; set; } public bool regulated { get; set; } public string telephone { get; set; } public string cellphone { get; set; } public string address { get; set; } public Code code { get; set; } } public class RespuestaCredencial { public bool result { get; set; } public string status { get; set; } public DatosAfiliadoCredencial datosAfiliadoCredencial { get; set; } } public class AutenticacionCredencial { public string access_token { get; set; } public string token_type { get; set; } public int expires_in { get; set; } public int user_id { get; set; } public string refresh_token { get; set; } }
-
Array to string conversion error in header
Currently working with laravel 8.And calling the api using httpclient but few of them i need to pass the bearer token in headers for which struggling from couple of hours seems like didn't work anything.
Any help will be appreciated. Thanks,
try { $token = array(Session::get('access_token')); $headers = [ 'Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json', ]; // echo "<pre>"; print_r($token); die(); if ( $data != null ) { $response = Http::withHeaders($headers)->asForm()->post($endpoint, $data); }else{ $response = Http::get($endpoint); } $result = $response->json(); echo "<pre>"; print_r($result);die(); $httpcode = $response->status(); $error_msg = ($response->serverError()) ?? ''; // echo "<pre>"; print_r($result);die(); if ( $error_msg == '' ) { $response = [ 'status' => true, 'result' => $result, 'status_code' => $httpcode ]; return $response ; } else { return [ 'status' => false, 'result' => [], 'status_code' => $httpcode, 'error' => $error_msg ]; } }
-
Obj-C POST JSON (body?)to endpoint problems
Using Postman on my Mac I have confirmed GET/POST works to my endpoint. On my iPad I am trying to do the same thing but only GET connects and returns data (just for testing).
In Postman I have key of devices and value of [{"name":"1","values":[121,182,243]}] From Postman I can Send and the physical object responds and the server returns an array of all devices and nothing else (which I do not require but that is how it goes). Postman does have x-www-form-urlencoded under Body. This works as expected from Postman.
From my iPad the following code always returns an error 400 which I think means I am providing something the server is not expecting.
+(void)makeRequest { NSError *error = nil; storedURL = [[NSUserDefaults standardUserDefaults] objectForKey:@"eb-ipaddress-saved"]; NSString *urlstring = [NSString stringWithFormat:@"http://%@",storedURL]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlstring] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; NSString *jsonPostBody = @"{\"devices\":[{\"name\":\"1\",\"values\":[121,182,243]}]}"; NSData *postData = [jsonPostBody dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]; NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]]; [request setHTTPMethod:@"POST"]; [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if(httpResponse.statusCode == 200) { NSError *parseError = nil; NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; NSLog(@"The response is - %@",responseDictionary); NSInteger success = [[responseDictionary objectForKey:@"success"] integerValue]; if(success == 1) { NSLog(@"SUCCESS"); } else { NSLog(@"FAILURE"); } } else { NSLog(@"Error"); } }]; [dataTask resume];
}
My 4 logs from above (removed for clarity) return: urlstring http://192.168.90.55:3000/dmx/set jsonPostBody {"devices":[{"name":"1","values":[121,182,243]}]} httpResponse 400 Error
I will eventually switch to variables in my POST when in production.
Thank you
-
Xamarin iOS: System.Net.Http.HttpRequestException: The network connection was lost
I issue a
POST
request with anHttpClient
. On iOS, if the user backgrounds the app while the request is in flight and foregrounds it again, I get the following exception:System.Net.Http.HttpRequestException: The network connection was lost. ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=53, NSUnderlyingError=0x2825ea880 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={_kCFStreamErrorCodeKey=53, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask .<10>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask .<10>" )
I don't have this issue on Android. This seems to be related to how iOS functions. Is it possible to make sure the post request keeps running even when the app is backgrounded?
P.S. The app supports iOS 15.4 and uses
NSUrlSession
for theHttpClient
implementation (i.e. no custom handlers). Additionally, I'm not using Forms. This is native app only. and the issue is happening on a physical device. -
How to add network fetch inside swift struct initializer
I'm trying to get data from an URL (1st network call), then make a 2nd network call to fetch image from the url in the first response, and present on tableview in swift.
The json from 1st network call contains 3 strings:
struct Item: Codable { var title: String? var image_url: String? var content: String }
What I need to do is, after json decoding and get this
[Item]
array, I also need to make network call for each item in it so I can also get theUIImage
for each of them and presenttitle, content and Image
on each cell.My question is, where is the best place to make the network call (in MVVM pattern)?
My first thought is in the
TableViewCell
:func configCell(item: Item) { titleLabel.text = item.title descriptionLable.text = item.content // fetch image service.fetchImage(with: item.image_url) { result in switch result { case .success(let image): DispatchQueue.main.async { [weak self] in if let image = image { self?.iconView.isHidden = false } } case .failure(let error): print(error.localizedDescription) return } } }
However, I'm not sure if this the right way/place to do so because it might cause wrong image attach to each cell. Also it couples network layer into view layer.
So my 2nd thought is, create a second model in the viewModel and make network call in it:
struct ImageItem: Codable { var title: String? var image_url: String? var content: String var image: Data? init(with item: Item) { self.title = item.title self.content = item.content ContentService().fetchImage(with: item.image_url) { result in switch result { case .success(let image): self.image = image?.pngData() case .failure(let error): print(error.localizedDescription) } } }
But that doesn't feel right either. Also seems like I can't make network call in struct initializer.
Could anyone help or give me advice about where to put this 2nd layer network call for fetching the image?