Xamarin Forms Delete Web Cache / Javascript Storage - xamarin.forms

I have an app that is using an http server to serve files to a Web View. The web viewers are caching image links which is causing broken images when their paths changes.
I can delete the web store on Android and UWP but I cannot figure out how to properly with iOS.
Android:
Android.Webkit.WebStorage.Instance.DeleteAllData();
UWP:
Windows.UI.Xaml.Controls.WebView.ClearTemporaryWebDataAsync();
I have tried the following with no luck:
NSHttpCookieStorage.SharedStorage.RemoveCookiesSinceDate(NSDate.DistantPast);
WKWebsiteDataStore.DefaultDataStore.FetchDataRecordsOfTypes(WKWebsiteDataStore.AllWebsiteDataTypes, (NSArray records) =>
{
for (nuint i = 0; i < records.Count; i++)
{
var record = records.GetItem<WKWebsiteDataRecord>(i);
WKWebsiteDataStore.DefaultDataStore.RemoveDataOfTypes(
websiteDataTypes: record.DataTypes,
date: new[] { record },
completionHandler: ()=> { });
}
for (nuint i = 0; i < records.Count; i++)
{
var record = records.GetItem<WKWebsiteDataRecord>(i);
WKWebsiteDataStore.DefaultDataStore.RemoveDataOfTypes(record.DataTypes,
new[] { record }, () => { Console.Write($"deleted: {record.DisplayName}"); });
}
});
NSUrlCache.SharedCache.RemoveAllCachedResponses();
NSUrlCache.SharedCache.DiskCapacity = 0;
NSUrlCache.SharedCache.MemoryCapacity = 0;

Found the answer at: https://gochannel.org/links/link/snapshot/640
Rewrote to Xamarin IOS
private void DeleteCachedFiles()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
{
NSHttpCookieStorage.SharedStorage.RemoveCookiesSinceDate(NSDate.DistantPast);
WKWebsiteDataStore.DefaultDataStore.FetchDataRecordsOfTypes(WKWebsiteDataStore.AllWebsiteDataTypes, (NSArray records) =>
{
for (nuint i = 0; i < records.Count; i++)
{
var record = records.GetItem<WKWebsiteDataRecord>(i);
WKWebsiteDataStore.DefaultDataStore.RemoveDataOfTypes(record.DataTypes,
new[] { record }, () => { Console.Write($"deleted: {record.DisplayName}"); });
}
});
NSUrlCache.SharedCache.RemoveAllCachedResponses();
}
else
{
// Remove the basic cache.
NSUrlCache.SharedCache.RemoveAllCachedResponses();
var cookies = NSHttpCookieStorage.SharedStorage.Cookies;
foreach (var c in cookies)
{
NSHttpCookieStorage.SharedStorage.DeleteCookie(c);
}
}
try
{
// Clear web cache
DeleteLibraryFolderContents("Caches");
// Remove all cookies stored by the site. This includes localStorage, sessionStorage, and WebSQL/IndexedDB.
DeleteLibraryFolderContents("Cookies");
// Removes all app cache storage.
DeleteLibraryFolder("WebKit");
}
catch (Exception ex)
{
App.UnhandledException(ex, $"Error deleting cache {ex.Message}");
}
}
private void DeleteLibraryFolder(string folderName)
{
var manager = NSFileManager.DefaultManager;
var library = manager.GetUrls(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User).First();
var dir = Path.Combine(library.Path, folderName);
manager.Remove(dir, out NSError error);
if (error != null)
{
App.UnhandledException(new Exception(error.Description), error.Description);
}
}
private void DeleteLibraryFolderContents(string folderName)
{
var manager = NSFileManager.DefaultManager;
var library = manager.GetUrls(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User).First();
var dir = Path.Combine(library.Path, folderName);
var contents = manager.GetDirectoryContent(dir, out NSError error);
if (error != null)
{
App.UnhandledException(new Exception(error.Description), error.Description);
}
foreach (var c in contents)
{
try
{
manager.Remove(Path.Combine(dir, c), out NSError errorRemove);
if (errorRemove != null)
{
App.UnhandledException(new Exception(error.Description), error.Description);
}
}
catch (Exception ex)
{
App.UnhandledException(ex, $"Error deleting folder contents: {folderName}{Environment.NewLine}{ex.Message}");
}
}
}

Related

Xamarin.Azure.Notification.Hub (3.1.1) crashing in iOS 16.1

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
try
{
string ConnectionString = AppConfiguration.NotificationHubConnectionString;
string hubPath = AppConfiguration.NotificationHubPath;
if (!string.IsNullOrEmpty(ApplicationContext.Instance.APIVersion))
{
ConnectionString = AppConfiguration.NotificationHubConnectionStringv2;
hubPath = AppConfiguration.NotificationHubPath2;
}
NSSet tags = null;
SBNotificationHub hub;
byte[] bytes = deviceToken.ToArray();
string[] hexArray = bytes.Select(b => b.ToString("x2")).ToArray();
var tokenString = string.Join(string.Empty, hexArray);
hub = new SBNotificationHub(ConnectionString, hubPath);
tags = new NSSet(new string[] {
Mvx.IoCProvider.Resolve<IDeviceIdentifier>()?.GetRestaurantId()?.ToLower() });
hub.UnregisterAll(deviceToken, error =>
{
if (error != null)
{
LazyServiceFromIOC<IAnalytics>.Instance.RequestedService?.LogEvent(Enums.CustomEvents.Notifications.ToString(), error.Description);
return;
}
hub.RegisterNative(deviceToken, tags, errorCallback =>
{
if (errorCallback != null)
{
LazyServiceFromIOC<IAnalytics>.Instance.RequestedService?.LogEvent(Enums.CustomEvents.Notifications.ToString(), errorCallback.Description);
}
});
});
Preferences.Set("DeviceTokens", tokenString);
PushNotificationManager.DidRegisterRemoteNotifications(deviceToken);
}
catch (Exception ex)
{
LazyServiceFromIOC<IAnalytics>.Instance.RequestedService?.LogException(nameof(RegisteredForRemoteNotifications), ex);
}
}
Xamarin.Azure.Notification.Hub (3.1.1) - iOS 16.1
App is crashing at RegisterNative method... This logic was working all this while..till ios was upgraded to 16 on ipad
What changed in iOS 16

javascript injected in tinymce editor by wordpress when gutenberg is desactivated

with a fresh install and up to date of wordpress (5.8.2), when I desactivate gutenberg editor, Wordpress add this javascript code in all TinyMCE editor (content, acf fields etc..)
I have no plugin and theme by default. I desactivate Gutenberg with code or with a plugin, no changes. Anyone have a tip ? thx
<script type="text/javascript">
var spector;
var captureOnLoad = false;
var captureOffScreen = false;
window.__SPECTOR_Canvases = [];
(function() {
var __SPECTOR_Origin_EXTENSION_GetContext = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.__SPECTOR_Origin_EXTENSION_GetContext = __SPECTOR_Origin_EXTENSION_GetContext;
if (typeof OffscreenCanvas !== 'undefined') {
var __SPECTOR_Origin_EXTENSION_OffscreenGetContext = OffscreenCanvas.prototype.getContext;
OffscreenCanvas.prototype.__SPECTOR_Origin_EXTENSION_OffscreenGetContext = __SPECTOR_Origin_EXTENSION_OffscreenGetContext;
OffscreenCanvas.prototype.getContext = function () {
var context = null;
if (!arguments.length) {
return context;
}
if (arguments.length === 1) {
context = this.__SPECTOR_Origin_EXTENSION_OffscreenGetContext(arguments[0]);
if (context === null) {
return context;
}
}
else if (arguments.length === 2) {
context = this.__SPECTOR_Origin_EXTENSION_OffscreenGetContext(arguments[0], arguments[1]);
if (context === null) {
return context;
}
}
var contextNames = ["webgl", "experimental-webgl", "webgl2", "experimental-webgl2"];
if (contextNames.indexOf(arguments[0]) !== -1) {
// context.canvas.setAttribute("__spector_context_type", arguments[0]);
// Notify the page a canvas is available.
var myEvent = new CustomEvent("SpectorWebGLCanvasAvailableEvent");
document.dispatchEvent(myEvent);
this.id = "Offscreen";
window.__SPECTOR_Canvases.push(this);
if (captureOnLoad) {
// Ensures canvas is in the dom to capture the one we are currently tracking.
if (false) {
spector.captureContext(context, 500, false, false);
captureOnLoad = false;
}
}
}
return context;
}
}
HTMLCanvasElement.prototype.getContext = function () {
var context = null;
if (!arguments.length) {
return context;
}
if (arguments.length === 1) {
context = this.__SPECTOR_Origin_EXTENSION_GetContext(arguments[0]);
if (context === null) {
return context;
}
}
else if (arguments.length === 2) {
context = this.__SPECTOR_Origin_EXTENSION_GetContext(arguments[0], arguments[1]);
if (context === null) {
return context;
}
}
var contextNames = ["webgl", "experimental-webgl", "webgl2", "experimental-webgl2"];
if (contextNames.indexOf(arguments[0]) !== -1) {
context.canvas.setAttribute("__spector_context_type", arguments[0]);
// Notify the page a canvas is available.
var myEvent = new CustomEvent("SpectorWebGLCanvasAvailableEvent");
document.dispatchEvent(myEvent);
if (captureOffScreen) {
var found = false;
for (var i = 0; i < window.__SPECTOR_Canvases.length; i++) {
if (window.__SPECTOR_Canvases[i] === this) {
found = true;
break;
}
}
if (!found) {
window.__SPECTOR_Canvases.push(this);
}
}
if (captureOnLoad) {
// Ensures canvas is in the dom to capture the one we are currently tracking.
if (this.parentElement || false) {
spector.captureContext(context, 500, false, false);
captureOnLoad = false;
}
}
}
return context;
}
})()</script>
It is very likely added by the Spector.js extension : same behaviour with the Spector extension enabled on Firefox (when switching editor, or after save) => disabling the extension solved the issue.

Xamarin Http Request Timeout Issue

I have a mobile application based on Xamarin and a Web API based on .Net Core. Mobile app consumes methods of Web API via HttpClient. The code below is my base method to call any Web API method and the point is I want to set a timeout but could not achieved to set the exact timeout value whatever I have implemented. Tried Timespan.FromSeconds() or TimeSpan.FromMilliseconds() etc. When client makes a request to Web API, a loader is displayed to lock UI and removed after API response. Some clients gave me a feedback that the loader is displayed forever and request never ends. Maybe, the server is unreachable in this particular time or internet connection is broken for client etc. All I want to set a timeout and break the request and display an alert message to client. Of course, I googled and tried too much as mentioned but no result. If anyone can help me, will be appreciated.
public async Task<BaseResponseModel> Post(BasePostModel postModel)
{
var responseModel = new BaseResponseModel();
var json = postModel.ToString();
var jsonParam = new StringContent(json, Encoding.UTF8, "application/json");
var isPosted = true;
var clientHandler = new HttpClientHandler()
{
AllowAutoRedirect = true,
};
var url = GetURL(postModel.UrlKey);
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
ContractResolver = new DefaultContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var client = new HttpClient(clientHandler);
//client.Timeout = TimeSpan.FromSeconds(10);
//var cancellationTokenSource = new CancellationTokenSource();
//cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("X-Env", "MOBILE_API");
AttachToken(ref client, responseModel.Id);
try
{
if (Preferences.ContainsKey("UserJwtExprieDate"))
{
var expiryDate = Preferences.Get("UserJwtExprieDate", null);
if (DateTime.Now > DateTime.Parse(expiryDate))
{
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
Page currPage = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
if (currPage as SigninForFactorOne != null)
{}
else
{
App.LogoutUser();
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
catch (Exception ex)
{
new AppException(ex, responseModel.Id, 500, "anonymous.user", "Unable to post data to API!");
isPosted = false;
}
finally
{
if (!isPosted)
{
responseModel.Error = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
responseModel.Message = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
}
}
return responseModel;
}
I've used the solution below to manually set a time-out which works fine.
internal class TimeOutHandler : DelegatingHandler
{
private readonly TimeSpan TimeOut;
public TimeOutHandler(TimeSpan timeOut) => TimeOut = timeOut;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
{
using (var ctTimeOut = CancellationTokenSource.CreateLinkedTokenSource(ct))
{
ctTimeOut.CancelAfter(TimeOut);
try
{
return await base.SendAsync(req, ctTimeOut.Token);
}
catch (OperationCanceledException) when (!ct.IsCancellationRequested)
{
throw new TimeoutException();
}
}
}
}
How to use
var interval = TimeSpan.FromSeconds(10);
var handler = new TimeOutHandler(interval)
{
InnerHandler = new HttpClientHandler()
};
var client = new HttpClient(handler);
For more information, check out: https://thomaslevesque.com/2018/02/25/better-timeout-handling-with-httpclient/

Getting Null data from google adwords api

I want to fetch location details for all the ads from google adwords but I am getting null entries.I am not able to get any data from adwords api .Help me in That as according to my knowledge there is not problem with my code and I am not able to find any solution for that.My code that I have tried is written below.
public void GetLocationAds()
{
AdWordsUser user = new AdWordsUser();
{
try
{
int offset = 0;
// Create selector.
using (CampaignCriterionService campaignCriterionService =
(CampaignCriterionService)user.GetService(AdWordsService.v201809.CampaignCriterionService))
{
Selector selector = new Selector()
{
fields = new string[]
{
CampaignCriterion.Fields.CampaignId,
CampaignCriterion.Fields.CampaignCriterionStatus,
//Location.Fields.LocationName,
//Location.Fields.CriteriaType,
//Location.Fields.ParentLocations,
//LocationCriterion.Fields.CanonicalName,
//LocationCriterion.Fields.CountryCode,
CampaignCriterion.Fields.IsNegative,
},
// predicates = new Predicate[]
//{
// Predicate.Equals( "CriteriaType","LOCATION"),
//},
paging = Paging.Default,
ordering = new OrderBy[]
{
OrderBy.Asc( CampaignCriterion.Fields.CampaignId)
}
};
CampaignCriterionPage page = new CampaignCriterionPage();
do
{
// Get the ad groups.
page = campaignCriterionService.get(selector);
// Display the results.
if (page != null && page.entries != null)
{
int j = selector.paging.startIndex;
foreach (CampaignCriterion campaignCriterion in page.entries)
{
var campaignId = campaignCriterion.campaignId;
bool IsLocation = campaignCriterion.isNegative;
var CampaignCriterionType = campaignCriterion.CampaignCriterionType;
}
}
else
{
Console.Write("No campaignCriterion were found.");
}
selector.paging.IncreaseOffset();
}
while (selector.paging.startIndex < page.totalNumEntries);
}
}
catch (Exception ex)
{
}
}
}
Kindly help me in that.

Delete Records from a database

I am trying to delete set of records under my ASP.NET Application - API Controller. Here is my code from API Controller:
public JsonResult Delete([FromBody]ICollection<ShoppingItemViewModel> vm)
{
if (ModelState.IsValid)
{
try
{
var items = Mapper.Map<IEnumerable<ShoppingItem>>(vm);
_repository.DeleteValues(items, User.Identity.Name);
return Json(null);
}
catch (Exception Ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(null);
}
}
else
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(null);
}
}
And here is my AngularJS Controller part taking care of this:
$scope.RemoveItems = function () {
$scope.isBusy = true;
$http.delete("/api/items", $scope.items)
.then(function (response) {
if (response.statusText == "OK" && response.status == 200) {
//passed
for (var i = $scope.items.length - 1; i > -1; i--) {
if ($scope.items[i].toRemove == true) {
$scope.items.splice(i, 1);
}
}
}
}, function (err) {
$scope.errorMessage = "Error occured: " + err;
}).finally(function () {
$scope.isBusy = false;
});
}
For unknown reason, this works like a charm in my POST method but not in the Delete Method. I believe that the problem might be caused by the fact, that DELETE method only accepts Integer ID?
If that is the case, what is the correct way how to delete multiple items with one call?

Resources