void CallBackVerifiedResponse(OAuthAccessToken at, TwitterResponse response)
{
if (at != null)
{
SerializeHelper.SaveSetting<TwitterAccess>("TwitterAccess", new TwitterAccess
{
AccessToken = at.Token,
AccessTokenSecret = at.TokenSecret,
ScreenName = at.ScreenName,
UserId = at.UserId.ToString()
});
}
}
private void ok_Click_1(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(pinText.Text))
MessageBox.Show("Please enter PIN");
else
{
try
{
var cb = new Action<OAuthAccessToken, TwitterResponse>(CallBackVerifiedResponse);
service.GetAccessToken(_requestToken, pinText.Text, CallBackVerifiedResponse);
}
catch
{
MessageBox.Show("Something is wrong with the PIN. Try again please.", "Error", MessageBoxButton.OK);
}
}
}
My problem in is here when I use NavigationService.GoBack() inside the CallBackVerifiedResponse method i'm getting unauthorized access exception, and if i use it inside of the click event, I CallBackVerifiedResponse is not triggered. Any ideas?
It's been solved by using UIThread
public static class UIThread
{
private static readonly Dispatcher Dispatcher;
static UIThread()
{
// Store a reference to the current Dispatcher once per application
Dispatcher = Deployment.Current.Dispatcher;
}
/// <summary>
/// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on
/// the current thread so it can be safely called without the calling method being aware of which thread it is on.
/// </summary>
public static void Invoke(Action action)
{
if (Dispatcher.CheckAccess())
action.Invoke();
else
Dispatcher.BeginInvoke(action);
}
}
After this static class
I have called it inside of
CallBackVerifiedResponse
like this
UIThread.Invoke(()=>NavigationService.GoBack());
You can use Dispatcher.BeginInvoke to access the UIThread
Dispatcher.BeginInvoke(() =>
{
NavigationService.GoBack();
});
Or you could use your own smart dispatcher, used like this:
SmartDispatcher.BeginInvoke(() =>
{
MissionAccomplished();
});
Coded something as the following:
{
using System.ComponentModel;
using System.Windows.Threading;
using System.Windows;
using System;
public static class SmartDispatcher
{
/// <summary>
/// A single Dispatcher instance to marshall actions to the user
/// interface thread.
/// </summary>
private static Dispatcher _instance;
/// <summary>
/// Backing field for a value indicating whether this is a design-time
/// environment.
/// </summary>
private static bool? _designer;
/// <summary>
/// Requires an instance and attempts to find a Dispatcher if one has
/// not yet been set.
/// </summary>
private static void RequireInstance()
{
if (_designer == null)
{
_designer = DesignerProperties.IsInDesignTool;
}
// Design-time is more of a no-op, won't be able to resolve the
// dispatcher if it isn't already set in these situations.
if (_designer == true)
{
return;
}
// Attempt to use the RootVisual of the plugin to retrieve a
// dispatcher instance. This call will only succeed if the current
// thread is the UI thread.
try
{
_instance = Application.Current.RootVisual.Dispatcher;
}
catch (Exception e)
{
throw new InvalidOperationException("The first time SmartDispatcher is used must be from a user interface thread. Consider having the application call Initialize, with or without an instance.", e);
}
if (_instance == null)
{
throw new InvalidOperationException("Unable to find a suitable Dispatcher instance.");
}
}
/// <summary>
/// Initializes the SmartDispatcher system, attempting to use the
/// RootVisual of the plugin to retrieve a Dispatcher instance.
/// </summary>
public static void Initialize()
{
if (_instance == null)
{
RequireInstance();
}
}
/// <summary>
/// Initializes the SmartDispatcher system with the dispatcher
/// instance.
/// </summary>
/// <param name="dispatcher">The dispatcher instance.</param>
public static void Initialize(Dispatcher dispatcher)
{
if (dispatcher == null)
{
throw new ArgumentNullException("dispatcher");
}
_instance = dispatcher;
if (_designer == null)
{
_designer = DesignerProperties.IsInDesignTool;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool CheckAccess()
{
if (_instance == null)
{
RequireInstance();
}
return _instance.CheckAccess();
}
/// <summary>
/// Executes the specified delegate asynchronously on the user interface
/// thread. If the current thread is the user interface thread, the
/// dispatcher if not used and the operation happens immediately.
/// </summary>
/// <param name="a">A delegate to a method that takes no arguments and
/// does not return a value, which is either pushed onto the Dispatcher
/// event queue or immediately run, depending on the current thread.</param>
public static void BeginInvoke(Action a)
{
if (_instance == null)
{
RequireInstance();
}
// If the current thread is the user interface thread, skip the
// dispatcher and directly invoke the Action.
if (_instance.CheckAccess() || _designer == true)
{
a();
}
else
{
_instance.BeginInvoke(a);
}
}
}
}
Related
Hi I am trying to build an application in xamarin forms using PCL. I am trying to logout user from my app if the app is idle more than 10minute or more.
I tried it by events that are called on the time when app is about to go to sleep state. But if the device screentimeout is set for never timeout then maybe It will never go to sleep. So how can I achieve this. I am new to xamarin forms. And as I am building the app for all the platforms I am confused how to manage this timeout?
For now I use the following approach. Might need to do some additional testing to make sure everything works as expected. For example I am not sure what will happen if the app (iOS or Android) is in the background for extended amounts of time. Will the timer still be called every second or not? Perhaps when using timers with a short enough expiration time (~5 minutes) this is no issue whatsoever? Etc...
I've based my approach on several pieces of code I found on the web (some Xamarin code, some Swift / Java code) - there didn't seem to be a good comprehensive solution.
Anyways, some preliminary testing suggests this approach works fine.
First I've created a singleton class called SessionManager. This class contains a timer (actually just a while loop that sleeps every second) and methods to start, stop and extend the timer. It will also fire an event if the session expiration timer is expired.
public sealed class SessionManager
{
static readonly Lazy<SessionManager> lazy =
new Lazy<SessionManager>(() => new SessionManager());
public static SessionManager Instance { get { return lazy.Value; } }
SessionManager() {
this.SessionDuration = TimeSpan.FromMinutes(5);
this.sessionExpirationTime = DateTime.FromFileTimeUtc(0);
}
/// <summary>
/// The duration of the session, by default this is set to 5 minutes.
/// </summary>
public TimeSpan SessionDuration;
/// <summary>
/// The OnSessionExpired event is fired when the session timer expires.
/// This event is not fired if the timer is stopped manually using
/// EndTrackSession.
/// </summary>
public EventHandler OnSessionExpired;
/// <summary>
/// The session expiration time.
/// </summary>
DateTime sessionExpirationTime;
/// <summary>
/// A boolean value indicating wheter a session is currently active.
/// Is set to true when StartTrackSessionAsync is called. Becomes false if
/// the session is expired manually or by expiration of the session
/// timer.
/// </summary>
public bool IsSessionActive { private set; get; }
/// <summary>
/// Starts the session timer.
/// </summary>
/// <returns>The track session async.</returns>
public async Task StartTrackSessionAsync() {
this.IsSessionActive = true;
ExtendSession();
await StartSessionTimerAsync();
}
/// <summary>
/// Stop tracking a session manually. The OnSessionExpired will not be
/// called.
/// </summary>
public void EndTrackSession() {
this.IsSessionActive = false;
this.sessionExpirationTime = DateTime.FromFileTimeUtc(0);
}
/// <summary>
/// If the session is active, then the session time is extended based
/// on the current time and the SessionDuration.
/// duration.
/// </summary>
public void ExtendSession()
{
if (this.IsSessionActive == false) {
return;
}
this.sessionExpirationTime = DateTime.Now.Add(this.SessionDuration);
}
/// <summary>
/// Starts the session timer. When the session is expired and still
/// active the OnSessionExpired event is fired.
/// </summary>
/// <returns>The session timer async.</returns>
async Task StartSessionTimerAsync() {
if (this.IsSessionActive == false) {
return;
}
while (DateTime.Now < this.sessionExpirationTime) {
await Task.Delay(1000);
}
if (this.IsSessionActive && this.OnSessionExpired != null) {
this.IsSessionActive = false;
this.OnSessionExpired.Invoke(this, null);
}
}
}
For the Android app I then:
Configure the SessionManager in the MainActivity to logout when the session expires.
Override the OnUserInteraction method in the MainActivity to extend the session timer on user interaction.
public class MainActivity /* ... */ {
protected override void OnCreate(Bundle bundle)
{
// ...
SessionManager.Instance.SessionDuration = TimeSpan.FromSeconds(10);
SessionManager.Instance.OnSessionExpired = HandleSessionExpired;
}
public override void OnUserInteraction()
{
base.OnUserInteraction();
SessionManager.Instance.ExtendSession();
}
async void HandleSessionExpired(object sender, EventArgs e)
{
await App.Instance.DoLogoutAsync();
}
}
For iOS I do the following:
Configure the SessionManager in the AppDelegate to logout when the session expires.
Add a custom gesture handler to the key window to extend the session timer on user interaction.
public partial class AppDelegate /* ... */
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
// ...
var success = base.FinishedLaunching(app, options);
if (success) {
SessionManager.Instance.SessionDuration = TimeSpan.FromSeconds(10);
SessionManager.Instance.OnSessionExpired += HandleSessionExpired;
var allGesturesRecognizer = new AllGesturesRecognizer(delegate
{
SessionManager.Instance.ExtendSession();
});
this.Window.AddGestureRecognizer(allGesturesRecognizer);
}
return success;
}
async void HandleSessionExpired(object sender, EventArgs e)
{
await App.instance.DoLogoutAsync();
}
class AllGesturesRecognizer: UIGestureRecognizer {
public delegate void OnTouchesEnded();
private OnTouchesEnded touchesEndedDelegate;
public AllGesturesRecognizer(OnTouchesEnded touchesEnded) {
this.touchesEndedDelegate = touchesEnded;
}
public override void TouchesEnded(NSSet touches, UIEvent evt)
{
this.State = UIGestureRecognizerState.Failed;
this.touchesEndedDelegate();
base.TouchesEnded(touches, evt);
}
}
}
Edit: Bolo asked a good question below, so I'll add it here. StartTrackSessionAsync is called as soon as the user is logged in. EndTrackSession should be called when the user is logged out of the app as well of course.
Tweaked #Wolfgang version
public sealed class SessionManager
{
static readonly Lazy<SessionManager> lazy =
new Lazy<SessionManager>(() => new SessionManager());
public static SessionManager Instance { get { return lazy.Value; } }
private Stopwatch StopWatch = new Stopwatch();
SessionManager()
{
SessionDuration = TimeSpan.FromMinutes(5);
}
public TimeSpan SessionDuration;
public void EndTrackSession()
{
if (StopWatch.IsRunning)
{
StopWatch.Stop();
}
}
public void ExtendSession()
{
if (StopWatch.IsRunning)
{
StopWatch.Restart();
}
}
public void StartTrackSessionAsync()
{
if (!StopWatch.IsRunning)
{
StopWatch.Restart();
}
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 2), () =>
{
if (StopWatch.IsRunning && StopWatch.Elapsed.Minutes >= SessionDuration.Minutes)
{
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
{
await Prism.PrismApplicationBase.Current.Container.Resolve<INavigationService>().NavigateAsync("/Index/Navigation/LoginPage");
});
StopWatch.Stop();
}
return true;
});
}
}
Under main activity added the below
public override void OnUserInteraction()
{
base.OnUserInteraction();
SessionManager.Instance.ExtendSession();
}
Unfortunately this is not really something that you can easily do on the client side. There is also no way to do it just from the PCL. There might be a plugin that you can add to your project, but I have not found one yet.
The reason for this is the difference in the way that iOS and Android handle the app life cycle. Both are very different. For instance once iOS suspends your application, there is really only 2 ways to wake it up. GPS location update and Push notification. In Android it is easier as they have the AlarmManager that you can register and intent with to do the logout for you.
My suggestion would be, if you control the api you are using, have the session expire server side so that any request that comes in after that 10 minutes would fail, and handle those failures appropriately on the client side.
If your concern is purely for when the app is in the foreground and active but not used, you will then have to implement a timer, and reset it every time there is some user interaction.
I was able to use the Device.StartTimer in Xamarin Forms to create an expiration. For my app the user switched screens fairly often so I would cause inactivity to be reset between screen transitions. It was a little less obnoxious then tying the method to each button press and screen tap. The class that houses the logic looks something like this:
public class InactivityService
{
public ActivityMonitorService( )
{
}
public DateTime LastClick { get; private set; }
public TimeSpan MaxLength { get; private set; }
public void Start(TimeSpan maxDuration, Action expirationCallback = null)
{
MaxLength = maxDuration;
Notify();
_expirationCallBack = expirationCallback;
ResetTimer();
}
public void Notify()
{
LastClick = DateTime.Now;
}
public void Stop()
{
}
public TimeSpan TimeSinceLastNotification()
{
var now = DateTime.Now;
var timeSinceLastClick = now - LastClick;
return timeSinceLastClick;
}
public TimeSpan GetNewTimerSpan()
{
var newDuration = MaxLength - TimeSinceLastNotification();
return newDuration;
}
public bool IsExpired(DateTime time)
{
return time - LastClick > MaxLength;
}
private bool CallBack()
{
if (IsExpired(DateTime.Now))
{
Expire();
}
else
{
ResetTimer();
}
return false;
}
public async void Expire()
{
if (_expirationCallBack != null)
_expirationCallBack.Invoke();
Stop();
//Notify user of logout
//Do logout navigation
}
private void ResetTimer()
{
Device.StartTimer(GetNewTimerSpan(), CallBack);
}
}
I have an Aspnet Web API project. I used repository pattern and I want to do dependency injection with ninject, but it's not working.
Ninject.Web.Common.cs
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(ProjectName.API.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(ProjectName.API.App_Start.NinjectWebCommon), "Stop")]
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFirstService>().To<ServiceManager>().WithConstructorArgument("firstServiceDAL", new EFFirstDAL());
}
}
Is Ninject.Web.Common class correct? Because it isn't working.
My api's response;
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'FirstController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
FirstController.cs - My controller's constructor
public class FirstController : ApiController
{
private readonly IFirstService _firstService;
public FirstController(IFirstService firstService)
{
this._firstService = firstService;
}
}
What can I do ?
It seems that you don't have a public parameterless constructor.Your FirstController has to have a public,parameterless default constructor.
Add following code into your FirstController.
public FirstController()
{
}
It would be better if you had shared your controller.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFirstService>().To<FirstService>();
}
I am using Windows 10 & Visual Studio 2015 for development and targeting Android, iOS, Windows Phone, Windows Universal.
I wanted to use XLabs SecureStorage Service.
I am using XLabs.Platform package 2.3.0-pre02.
at this line i am getting exception (only for UWP)
secureStorage.Store(key, Encoding.UTF8.GetBytes(value));
And Exception Details are :
FileName : System.Runtime.WindowsRuntime, Version=4.0.11.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
HResult : -2146234304
HelpLink : null
InnerException : null
Message : Could not load file or assembly 'System.Runtime.WindowsRuntime, Version=4.0.11.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Source : XLabs.Platform.UWP
SourceTrack : at XLabs.Platform.Services.SecureStorage.d__6.MoveNext()
at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.StartTStateMachine
at XLabs.Platform.Services.SecureStorage.Store(String key, Byte[] dataBytes)
at UWPTest.SecureStorageService.Store(String key, String value, Boolean overwrite)
After some trial and error i am able to run SecureStorage service successfully on Xamarin UWP.
SecureStorage.cs(Code)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ABC.UWP.Common
{
using System;
using System.IO;
using Windows.Storage;
using System.Threading;
using System.Runtime.InteropServices.WindowsRuntime;
using XLabs.Platform.Services;
using Windows.Security.Cryptography.DataProtection;
/// <summary>
/// Implements <see cref="ISecureStorage"/> for WP using <see cref="IsolatedStorageFile"/> and <see cref="ProtectedData"/>.
/// </summary>
public class SecureStorage : ISecureStorage
{
private static Windows.Storage.ApplicationData AppStorage { get { return ApplicationData.Current; } }
private static Windows.Security.Cryptography.DataProtection.DataProtectionProvider _dataProtectionProvider = new DataProtectionProvider();
private readonly byte[] _optionalEntropy;
/// <summary>
/// Initializes a new instance of <see cref="SecureStorage"/>.
/// </summary>
/// <param name="optionalEntropy">Optional password for additional entropy to make encyption more complex.</param>
public SecureStorage(byte[] optionalEntropy)
{
this._optionalEntropy = optionalEntropy;
}
/// <summary>
/// Initializes a new instance of <see cref="SecureStorage"/>.
/// </summary>
public SecureStorage() : this(null)
{
}
#region ISecureStorage Members
/// <summary>
/// Stores the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="dataBytes">The data bytes.</param>
public async void Store(string key, byte[] dataBytes)
{
//var mutex = new Mutex(false, key);
using (var mutex = new Mutex(false, key))
{
try
{
mutex.WaitOne();
var buffer = dataBytes.AsBuffer();
if (_optionalEntropy != null)
{
buffer = await _dataProtectionProvider.ProtectAsync(buffer);
}
var file = await AppStorage.LocalFolder.CreateFileAsync(key, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBufferAsync(file, buffer);
}
catch (Exception ex)
{
throw new Exception(string.Format("No entry found for key {0}.", key), ex);
}
}
//finally
//{
// mutex.ReleaseMutex();
//}
}
/// <summary>
/// Retrieves the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>System.Byte[].</returns>
/// <exception cref="System.Exception"></exception>
public byte[] Retrieve(string key)
{
var mutex = new Mutex(false, key);
try
{
mutex.WaitOne();
return Task.Run(async () =>
{
var file = await AppStorage.LocalFolder.GetFileAsync(key);
var buffer = await FileIO.ReadBufferAsync(file);
if (_optionalEntropy != null)
{
buffer = _dataProtectionProvider.UnprotectAsync(buffer).GetResults();
}
return buffer.ToArray();
}).Result;
}
catch (Exception ex)
{
throw new Exception(string.Format("No entry found for key {0}.", key), ex);
}
finally
{
mutex.ReleaseMutex();
}
}
/// <summary>
/// Deletes the specified key.
/// </summary>
/// <param name="key">The key.</param>
public void Delete(string key)
{
var mutex = new Mutex(false, key);
try
{
mutex.WaitOne();
Task.Run(async () =>
{
var file = await AppStorage.LocalFolder.GetFileAsync(key);
await file.DeleteAsync();
});
}
finally
{
mutex.ReleaseMutex();
}
}
/// <summary>
/// Checks if the storage contains a key.
/// </summary>
/// <param name="key">The key to search.</param>
/// <returns>True if the storage has the key, otherwise false. </returns>
public bool Contains(string key)
{
try
{
return Task.Run(async() => await AppStorage.LocalFolder.GetFileAsync(key)).Result.IsAvailable;
}
catch
{
return false;
}
}
#endregion
}
}
I'm doing a login view. Problem is that the PasswordBox cant be binded to the view model so im mapping a property of the view to the viewmodel.
This is the View
public partial class LoginView : MetroDataWindow
{
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
public LoginView()
: this(null) { }
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
/// <param name="viewModel">The view model to inject.</param>
/// <remarks>
/// This constructor can be used to use view-model injection.
/// </remarks>
public LoginView(LoginViewModel viewModel)
: base(viewModel)
{
InitializeComponent();
}
[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewToViewModel)]
public SecureString Contrasena
{
get { return (SecureString)GetValue(ContrasenaPropiedad); }
set { SetValue(ContrasenaPropiedad, value); }
}
// Using a DependencyProperty as the backing store for MapCenter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContrasenaPropiedad = DependencyProperty.Register("Contrasena", typeof(SecureString),
typeof(LoginView), new PropertyMetadata(null, (sender, e) => ((LoginView)sender).UpdateContrasena()));
private void UpdateContrasena()
{
MessageBox.Show("VIEW: FirstName changed to " + ContrasenaPropiedad.ToString());
}
private void tbPassword_PasswordChanged(object sender, RoutedEventArgs e)
{
Contrasena = tbPassword.SecurePassword;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ContrasenaPropiedad)
{
int i = 0;
}
}
}
this is the viewmodel part with the property
public static readonly PropertyData ContrasenaPropiedad = RegisterProperty("Contrasena", typeof(SecureString), null, (sender, e) => ((LoginViewModel)sender).OnContrasenaChange());
public void OnContrasenaChange()
{
_messageService.Show("VIEW MODEL: FirstName changed to " + Contrasena.ToString());
}
public SecureString Contrasena
{
get
{
return GetValue<SecureString >(ContrasenaPropiedad);
}
set
{
SetValue(ContrasenaPropiedad, value);
}
}
the onChange function of the viewmodel never triggers.
I based this code on the example given in the last comment in this question
Catel ViewToViewModel attribute
But it does not work. Am I missing something or was the bug commented there never fixed?
Also since the view is the only one changing the property should i use the ViewToViewModelMappingType.ViewToViewModel type instead? does it change the implementation of the mapping in any way?
Passwords are a special kind of breed. But Catel has a solution for that problem, the UpdateBindingOnPasswordChanged behavior:
<PasswordBox>
<i:Interaction.Behaviors>
<catel:UpdateBindingOnPasswordChanged Password="{Binding Password, Mode=TwoWay}" />
</i:Interaction.Behaviors>
</PasswordBox>
ps. are you aware of Catel.Fody? It makes your code more readable and easier to write.
I've a question regarding cache in mvc web application.
I'd like to use cache to store many lists which are used frequently in this way
List<IncotermDTO> incoterm;
string keyIncoterm = "listaIncoterm";
if (!CacheHelper.Get(keyIncoterm, out incoterm))
{
incoterm = BLIncoterm.GetIncoterm(null, null);
CacheHelper.Add(incoterm, keyIncoterm);
}
ViewBag.listaIncoterm = new SelectList(incoterm.OrderBy(x => x.DESCRIPTION), "ID", "DESCRIPTION");
following the tips in this article
http://johnnycoder.com/blog/2008/12/10/c-cache-helper-class/
This is the class helper
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
namespace GestioneMovimentazioni
{
public static class CacheHelper
{
/// <summary>
/// Insert value into the cache using
/// appropriate name/value pairs
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="o">Item to be cached</param>
/// <param name="key">Name of item</param>
public static void Add<T>(T o, string key)
{
// NOTE: Apply expiration parameters as you see fit.
// I typically pull from configuration file.
// In this example, I want an absolute
// timeout so changes will always be reflected
// at that time. Hence, the NoSlidingExpiration.
HttpContext.Current.Cache.Insert(
key,
o,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromSeconds(120));
}
/// <summary>
/// Remove item from cache
/// </summary>
/// <param name="key">Name of cached item</param>
public static void Clear(string key)
{
HttpContext.Current.Cache.Remove(key);
}
/// <summary>
/// Check for item in cache
/// </summary>
/// <param name="key">Name of cached item</param>
/// <returns></returns>
public static bool Exists(string key)
{
return HttpContext.Current.Cache[key] != null;
}
/// <summary>
/// Retrieve cached item
/// </summary>
/// <typeparam name="T">Type of cached item</typeparam>
/// <param name="key">Name of cached item</param>
/// <param name="value">Cached value. Default(T) if
/// item doesn't exist.</param>
/// <returns>Cached item as type</returns>
public static bool Get<T>(string key, out T value)
{
try
{
if (!Exists(key))
{
value = default(T);
return false;
}
value = (T)HttpContext.Current.Cache[key];
}
catch
{
value = default(T);
return false;
}
return true;
}
public static T Get<T>(string key) where T : class
{
try
{
return (T)HttpContext.Current.Cache[key];
}
catch
{
return null;
}
}
}
}
This is the question..
This list will be cached for all users of the application or not?
If not, what implementation do you suggest?
HttpContext.Current.Cache is the same for all users. At least as long as you do not use Loadbalancing or Webfarm..