Content Available missing in moon-apns payload - push-notification

I need to send a payload using moon-apns.
currently i can see that the payload structure of NotificationPayload is like below-
public class NotificationPayload
{
public NotificationPayload(string deviceToken);
public NotificationPayload(string deviceToken, string alert);
public NotificationPayload(string deviceToken, string alert, int badge);
public NotificationPayload(string deviceToken, string alert, int badge, string sound);
public NotificationAlert Alert { get; set; }
public int? Badge { get; set; }
public Dictionary<string, object[]> CustomItems { get; }
public string DeviceToken { get; set; }
public string Sound { get; set; }
public void AddCustom(string key, params object[] values);
public string ToJson();
public override string ToString();
}
Where is Content-Available? it must be the part of aps.. Is it missing or not available in moon-apns? if so how to send Content-Available as a part of aps as showed in below example-
{"aps":{"alert":"Helo","badge":1,"content-available" : 1,"sound":"default"}}
I tried Add custom ; but it adds custom property outside the aps string.

I have used below method in Node.js. It's working to me.
agent.createMessage().device(device).contentAvailable('1').alert("loc-key","Title": "Message").send();

Related

Xamarin Forms SQLLite add OneToOne and OneToMany subobjects to db

Im trying to create a persistent sqllite db (creation tables once you install the app, deletion of db when you uninstall app)
I have a issue that I cant save my sub objects for example
public class ObjectInstanceResponseModel : GenericResponseModel
{
public ObservableCollection<ObjectInstanceData> ObjectInstances { get; set; }
}
public class ObjectInstanceData : GenericResponseModel
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[JsonProperty("idObjectinstance")]
public int IdObjectInstance { get; set; }
[JsonProperty("objectclass_idObjectclass")]
public int ObjectClassIdObjectClass { get; set; }
[JsonProperty("objectclassname")]
public string ObjectClassName { get; set; }
[JsonProperty("visibilitylevel")]
public int VisibilityLevel { get; set; }
[JsonProperty("showname")]
public bool ShowName { get; set; }
[JsonProperty("showicon")]
public bool ShowIcon { get; set; }
[JsonProperty("creationtime")]
public DateTimeOffset CreationTime { get; set; }
[JsonProperty("users_idUsers")]
public int UsersIdUsers { get; set; }
[JsonProperty("isfavorite")]
public bool? IsFavorite { get; set; }
[OneToMany("ObjectInstanceDataStrings")]
[JsonProperty("strings")]
public List<String> Strings { get; set; }
}
public class String
{
[PrimaryKey, AutoIncrement]
[JsonProperty("idObjectparameterstring")]
public int? IdObjectParameterString { get; set; }
[ForeignKey(typeof(ObjectInstanceData))]
public int ObjectInstanceDataStrings { get; set; }
[JsonProperty("stringvalue")]
public string StringValue { get; set; }
[JsonProperty("objectparameterset_idObjectparameterset")]
public int? ObjectParameterSetIdObjectParameterSet { get; set; }
[JsonProperty("showinballon")]
public bool? ShowInBallon { get; set; }
[JsonProperty("idClassparameter")]
public int IdClassParameter { get; set; }
[JsonProperty("classparametername")]
public string ClassParameterName { get; set; }
}
So, my class String is always empty, although there are some rows in the table that I created Strings..
Am I need a lazy loading for this?
I implemented sqllite through depedency service in my app.cs like this:
public partial class App : Application
{
public static SQLiteConnection DatabaseConnection { get; set; }
public App()
{
InitializeComponent();
DatabaseConnection = DependencyService.Get<IConnection>().GetConnection();
CreateTables();
}
private void CreateTables()
{
DatabaseConnection.CreateTable<ObjectInstanceData>();
DatabaseConnection.CreateTable<Models.Objects.String>();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
So, basically the logic should be when no internet, work with sql lite (keep local changes), and when internet come back upload that changes that kept in db, and erase data from tables.
You noticed that Im using response model for api.
So, Im calling from my FavoriteObjectViewModel this:
var response = await ApiServiceProvider.GetObjectInstances(null, true);
and in the ApiServiceProvider:
public static async Task<ObjectInstanceResponseModel> GetObjectInstances(string queryString = null, bool? onlyFavorites = null)
{
HttpResponseMessage response;
response = await apiClient.GetAsync(objectInstancesEndpoint);
var resultContent = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ObservableCollection<ObjectInstanceData>>(resultContent);
objectInstanceResponse.ObjectInstances = result;
//after each api call I need to update db
//delete previous data, and add fresh data from api
App.DatabaseConnection.DeleteAll<ObjectInstanceData>();
foreach (var item in result)
{
App.DatabaseConnection.Insert(item);
if (item.Strings != null && item.Strings.Count > 0)
App.DatabaseConnection.InsertAll(item.Strings);
}
//I only get the data for ObjectInstanceData, Strings model is empty!
var objectsResponseDb = App.DatabaseConnection.GetAllWithChildren<ObjectInstanceData>();
objectInstanceResponse.Succeeded = true;
return objectInstanceResponse;
}
So, my questions are:
If I create tables each time in App.cs is that mean, that I not store data, when user quit application, and re-enter again?
Why is the model Strings empty? When I invoke var strings = App.DatabaseConnection.GetAllWithChildren<Models.Objects.String>(); I can see that there is data?
What is the best approach for doing offline "logging"? maybe there is a some better nuget for sqllite?
I don't know much about persistent databases but one thing I can tell you for sure:you're approach is wrong.
You should create a separate class for the database's logic like creating tables and instantiating the connection along with other methods for manipulating data.
In the App class you can create a static resource of the database class which you can call it and make use of the methods in it.
I'm not very good with explaining but here it is a very basic example of how it should look:https://learn.microsoft.com/en-us/xamarin/get-started/tutorials/local-database/?tutorial-step=2&tabs=vswin.

Looking for a way to change http request and add user id on body data

I am working on a web API where login is required in order to do any other action, so I am using identity with role-based authentication.
What I would like to achieve is to override the user id into the request body before the controller's action only in cases where the request type implements a certain interface.
For example, I have these view model
public class UserVM : IVMLogging {
public Guid? ID { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public bool IsActive { get; set; }
public Guid Role { get; set; }
public string LastModifiedBy { get; set; }
}
public class OptionVM : IVMLogging {
public Guid? ID { get; set; }
public string Name { get; set; }
public string LastModifiedBy { get; set; }
}
And this interface
public interface IVMLogging {
string LastModifiedBy { get; set; }
}
In both cases property LastModifiedBy is where I want store the user id (ignoring the value coming from client).
Is this possible to be done?
While you can use middleware to modify an inbound request on the way to the controller, the work to try to inspect, serialize, and deserialize the body type is probably more trouble than it's worth. Your controllers can modify the contents of the view model on return if there are any properties that you'd like to update, like attaching the user:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[HttpPost]
public IActionResult Post(Foo foo)
{
foo.Qux = HttpContext.User.Identity.Name; // Use the identity name
foo.Qux = HttpContext.User.FindFirst("claimName").Value; // grab a claim value
// do whatever actions
}
...
Your controller will have access to the HTTP context and can grab the current identity or claims and add them where you want them before you process your viewmodel.
If this is something you find yourself doing regularly, you could add an extension for it for your interface:
public static class FooExtensions
{
public static IFoo SetFooUser(this IFoo foo, ClaimsPrincipal claimsPrincipal)
{
foo.Qux = claimsPrincipal.Identity.Name;
return foo;
}
}
Which can then be called more simply with foo.SetFooUser(HttpContext.User) in your controller as long as it implements the interface.

sending an object array to a get function

I'm using .NET Core and WebApi and I am trying to figure out what the url would look like to send an array of objects through.
For example
public class DataObject
{
public int id { get; set;}
public string name { get; set }
}
[HttpGet()]
public <ActionResult<string>> GetSomething(DataObject[] data))
{
//do something and return a string
}
what would the url look like to do this? Should I use FromQuery or FromRoute on data? On the HttpGet(), what should be in the parenthesis? "{data}" or something else?
Everything I can find so far has been on integer arrays or string arrays, but not complex arrays to a get call.
Update
Still not able to get this to work even though I'm sure the reply I have gotten should work. Here is some more code.
[Route("api/[controller]/[action]")]
[HttpGet()]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GridResult), (int)HttpStatusCode.OK)]
public async Task<ActionResult<GridResult>> GetGridData<TFilter1, TFilter2, TItem1>
([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1, [FromQuery] TFilter2[] TFilters2, [FromQuery] TItem1[] TSorts)
and finally the url that I have generated that throws a 404.
https://localhost:44366/api/grid/GetGridData/sessionID=598357390&details?NUMBER_OF_ROWS_FIRST_RETURNED=100&CURSOR_POSITION=0&RESULT_IN_SAXORDER=false&TERSERESPONSE=true&IsStaticList=true&GRID_TYPE=list&REQUEST_TYPE=LIST.DATA_ONLY.STORED&GRID_NAME=WUWP09&TFilters1[0].AliasName=PRO_CODE&TFilters1[0].Operator=%3D&TFilters1[0].SEQNUM=1&TFilters1[1].AliasName=APR_CLASS&TFilters1[1].Operator=%3D&Tsorts[1].SEQNUM=2&Tsorts[0].ALIAS_NAME=pvd_value&Tsorts[0].TYPE=ASC
Update 2
https://localhost:44366/api/grid/GetGridData?sessionID=598357390&details.NUMBER_OF_ROWS_FIRST_RETURNED=100&details.CURSOR_POSITION=0&details.RESULT_IN_SAXORDER=false&details.TERSERESPONSE=true&details.IsStaticList=true&details.GRID_TYPE=list&details.REQUEST_TYPE=LIST.DATA_ONLY.STORED&details.GRID_NAME=WUWP09&details.TAB_NAME&details.LOCALIZE_RESULT&details.USER_FUNCTION_NAME&details.TOTALRECORDS&details.RES_IsMoreRecords&details.RES_CURRENT_CURSOR_POSITION&TFilters1[0].AliasName=PRO_CODE&TFilters1[0].Operator=%3D&TFilters1[0].SEQNUM=1&TFilters1[1].AliasName=APR_CLASS&TFilters1[1].Operator=%3D&Tsorts[1].SEQNUM=2&Tsorts[0].ALIAS_NAME=pvd_value&Tsorts[0].TYPE=ASC
Update 3
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var _accessor = services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var config = new GridServices.Models.config();
Configuration.Bind("Connections", config);
services.AddSingleton(config);
services.AddSingleton(new Controllers.GridController(config));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
}
GridController
namespace EAMWebApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class GridController : ControllerBase
{
config Config { get; }
//private readonly LinkGenerator _linkGenerator;
public GridController(config config)
{
config = Config;
//_linkGenerator = linkGenerator;
}
[HttpGet()]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(GridResult), (int)HttpStatusCode.OK)]
public async Task<ActionResult<GridResult>> GetGridData<TFilter1, TFilter2, TItem1>
([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1 = null, [FromQuery] TFilter2[] TFilters2 = null, [FromQuery] TItem1[] TSorts = null)
{//Do something}
}
GridDetails
namespace GridServices.Models
{
public class GridDetails
{
public string GRID_NAME { get; set; }
public string NUMBER_OF_ROWS_FIRST_RETURNED { get; set; }
public string CURSOR_POSITION { get; set; }
public string TAB_NAME { get; set; }
public string RESULT_IN_SAXORDER { get; set; }
public string TERSERESPONSE { get; set; }
public string LOCALIZE_RESULT { get; set; }
public string USER_FUNCTION_NAME { get; set; }
public string TOTALRECORDS { get; set; }
public bool RES_IsMoreRecords { get; set; }
public bool IsStaticList { get; set; }
public string GRID_TYPE { get; set; }
public string REQUEST_TYPE { get; set; }
public string RES_CURRENT_CURSOR_POSITION { get; set; }
}
}
MultiAddOnFilter
public class MultiAddOnFilter
{
public string ALIAS_NAME { get; set; }
public string OPERATOR { get; set; }
public string OPERATORSpecified { get; set; }
public string VALUE { get; set; }
public string LPAREN { get; set; }
public string RPAREN { get; set; }
public string JOINER { get; set; }
public string JOINERSpecified { get; set; }
public string SEQNUM { get; set; }
public MultiAddOnFilter(string _ALIAS_NAME, string _OPERATOR, string _VALUE)
{
ALIAS_NAME = _ALIAS_NAME;
OPERATOR = _OPERATOR;
OPERATORSpecified = "true";
VALUE = _VALUE;
}
}
Sorts
namespace GridServices.Models
{
public class Sort
{
public string ALIAS_NAME { get; set; }
public string TYPE { get; set; }
public string TYPESpecified { get; set; }
public Sort(string _ALIAS_NAME, string _TYPE)
{
ALIAS_NAME = _ALIAS_NAME;
TYPE = _TYPE;
TYPESpecified = "true";
}
}
}
what would the url look like to do this?
It should be something like the following:
GET /Somecontroller/GetSomething?data[0].id=1&data[0].name=nameA&data[1].id=2&data[1].name=nameB&data[2].id=3&data[2].name=nameC
This payload is almost the same as you post in application/x-www-form-urlencoded format, except you'll send it as a querystring.
[Edit]
If one of those items were to be empty, would I have to pass %00 to it to indicate a null value?
Let's say you have such an object array:
data = [
{
"id": 1,
"name": "nameA"
},
{
"id": 2,
"name": null
},
{
"id": 3,
"name": "nameC"
}
]
Note the data[1].name==null. you don't have to specify data[1].name :
?data[0].id=1&data[0].name=nameA&data[1].id=2&data[2].id=3&data[2].name=nameC
If the whole data[1] item is null, just adjust the index of data[2] to data[1]:
data[0].id=1&data[0].name=nameA&data[1].id=3&data[1].name=name
Or you could add an empty field for this item:
?data[0].id=1&data[0].name=nameA&data[1].id=&data[2].id=3&data[2].name=nameC
What if the whole DataObject was null? /GetSomething?data=%00 ?
you don't have to specify /GetSomething?data=%00, just send a request to /GetSomething?, and then you'll get an empty array.
[Edit2]
There're two reasons that always routes you to a 404 result:
You're registering your GridController as a singleton. MVC will register controllers automatically (as a scoped service). Just remove that line :
services.AddSingleton(new Controllers.GridController(config));
Your controller action of GetGridData<TFilter1, TFilter2, TItem1> is a generic method. It won't work by default. There's already a thread on SO talking about this. I would also suggest you use a specific GridFilter type for each method. If you find yourself repeating the same logic, you could put your generic method into a parent MySupperGridBaseController<TFilter1, TFilter2, TItem1> class, something as below:
public class MySupperGridBaseController<TFilter1, TFilter2, TItem1> : ControllerBase
{
public async Task<ActionResult<GridResult>> GetGridData
([FromQuery]string sessionID, [FromQuery] GridDetails details, [FromQuery] TFilter1[] TFilters1 = null, [FromQuery] TFilter2[] TFilters2 = null, [FromQuery] TItem1[] TSorts = null)
{
...
}
}
// now we could reuse the same logic inherited from parent
public class GridController : MySupperGridBaseController<MultiAddOnFilter, MultiAddOnFilter, Sort>
{
}

Using Firesharp in Xamarin.Forms to get Data from Firebase Database

I want to push and get Recipe-Data from my Firebase Database in Xamarin.Forms with the Firesharp Plugin.
My Model Class is the Recipe Class:
public class Recipe
{
public string title { get; set; }
public string workTime { get; set; }
public string degreeOfDifficulty { get; set; }
public string caloriesPerPerson { get; set; }
public string preparation { get; set; }
public string cookingBakingTime { get; set; }
public string restTime { get; set; }
public int portions { get; set; }
public string pictureSource { get; set; }
public List<Ingredient> ingredients { get; set; }
public Recipe()
{
ingredients = new List<Ingredient>();
}
}
So Push Recipe-Objects to the Firebase DB works:
public async Task PushRecipe(Recipe recipe)
{
IFirebaseClient client = new FirebaseClient(config);
client.Push("Recipes", recipe);
}
Firebase Example
But when i want to get Data from the Database i get an Error..
public async Task<List<Recipe>> GetAllRecipes()
{
IFirebaseClient client = new FirebaseClient(config);
FirebaseResponse response = await client.GetAsync("Recipes");
try
{
List<Recipe> recipelist = response.ResultAs<List<Recipe>>();
return recipelist;
} catch (Exception e){
}
return null;
}
After this:
List<Recipe> recipelist = response.ResultAs<List<Recipe>>();
this Exception comes..
"{Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[dignaBon_App.Models.Recipe]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correc…}"
I don´t understand why i can´t get Data from the Database back..
Can someone help me?
You need instatiate the "config" with your firebase secret address key. Go to your Firebase console for this.

ASP.NET web API casting http response to json array

My Code works fine when calling REST URL:
http://api.feedzilla.com/v1/categories.json
but when I call following URL I get error:
http://api.feedzilla.com/v1/categories/15/articles.json?count=36&since=2012-11-15&client_source=&order=relevance&title_only=0&
Error:
{"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.IEnumerable`1[Nitin.News.DAL.Resources.Article]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'articles', line 1, position 12."}
My Code is as follows:
public class Article
{
public string publish_date { get; set; }
public string source { get; set; }
public string source_url { get; set; }
public string summary { get; set; }
public string title { get; set; }
public string url { get; set; }
}
public IEnumerable<Article> Get()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://api.feedzilla.com/v1/");
//Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// call the REST method
HttpResponseMessage response = client.GetAsync("http://api.feedzilla.com/v1/categories/2/articles.json??count=36&since=2012-11-15&client_source=&order=relevance&title_only=0&").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
return response.Content.ReadAsAsync<IEnumerable<Article>>().Result;
//wont work
//string JSON =response.Content.ReadAsStringAsync().Result;
//return JsonConvert.DeserializeObject<IEnumerable<T>>(JSON);
}
else
{
throw new Exception(string.Format("Data access faild,{0} ({1}) method:{2}", (int)response.StatusCode, response.ReasonPhrase, MethodURL));
}
}
You need another level in your object hierachy... i.e. a root to contain the IEnumerable.
Runing the JSON into the tool at http://json2csharp.com/ generates the following proxy classes:
public class Enclosure
{
public int length { get; set; }
public string media_type { get; set; }
public string uri { get; set; }
}
public class Article
{
public string author { get; set; }
public string publish_date { get; set; }
public string source { get; set; }
public string source_url { get; set; }
public string summary { get; set; }
public string title { get; set; }
public string url { get; set; }
public List<Enclosure> enclosures { get; set; }
}
public class RootObject
{
public List<Article> articles { get; set; }
public string description { get; set; }
public string syndication_url { get; set; }
public string title { get; set; }
}
You just need to change your code to this then:
// Parse the response body. Blocking!
return response.Content.ReadAsAsync<RootObject>().Result.articles;
Obviously strip out any properties you dont need. Just thought I would show them all out of interest.

Resources