Cosmos DB - CreateCollectionIfNotExistsAsync Generic method - c#

I am using cosmos DB and I have created below generic repository for CRUD operations.
public class CosmosDBRepository : ICosmosDBRepository
{
private readonly DocumentClient _client;
private readonly string DatabaseId = "FleetHub";
public CosmosDBRepository()
{
var endpoint = CloudConfigurationManager.GetSetting("CosmoDbEndpoint");
var authkey = CloudConfigurationManager.GetSetting("CosmoDbAuthKey");
try
{
if (endpoint == null || authkey == null)
{
throw new ArgumentNullException("CosmoDbEndpoint or CosmoDbAuthKey could not be found in the config file, check your settings.");
}
if (_client == null)
{
_client = new DocumentClient(new Uri(endpoint), authkey, connectionPolicy: new ConnectionPolicy { EnableEndpointDiscovery = false });
}
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
catch (Exception e)
{
throw new Exception($"Initialise failed CosmoDbEndpoint {endpoint} or CosmoDbAuthKey {authkey} could not be found in the config file, check your settings. {e.Message}");
}
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="partitionkey"></param>
/// <returns></returns>
public async Task<T> GetItemAsync<T>(string id, string partitionkey) where T : class
{
try
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
Document document = await _client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionkey) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> CreateItemAsync<T>(T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByDesc, int takeCount = -1)
where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
var criteria = _client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), new FeedOptions { EnableCrossPartitionQuery = true })
.Where(predicate)
.OrderByDescending(orderByDesc)
.AsDocumentQuery();
IDocumentQuery<T> query = criteria;
List<T> results = new List<T>();
while (query.HasMoreResults)
{
if (takeCount > -1 && results.Count >= takeCount)
{
break;
}
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> UpdateItemAsync<T>(string id, T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
#region private methods
private async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await _client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await _client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private string GetPartitionKeyAttributeCosmoDbCollection(Type t)
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.PartitionKey;
}
private string GetAttributeCosmoDbCollection<T>(Type t) where T : class
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.Name;
}
#endregion
}
Here is CosmoDBCollection class:
public class CosmoDBCollection : Attribute
{
public string Name { get; set; }
public string PartitionKey { get; set; }
}
I am calling CreateCollectionIfNotExistsAsync().Wait(); in the constructor and this method required collectionId. How Can I pass CollectionId to this method? As this is the generic repository.
Do I need to create a Generic CreateCollectionIfNotExistsAsync() method?

If your collection name is based off <T>, why not simply have CosmosDBRepository<T> as the actual class. That way you can get the value also on the constructor.
Ideally it would also be a readonly private property that you only calculate once (on the constructor) and reuse on all operations to avoid paying the cost to construct it later on (since it doesn't change).

Related

Convert string to IMemoryOwner / Copy string into a rented buffer

I have a custom memory sequence OwnedMemorySequence. I want to put a string inside. The issue is that I cannot get it to compile. Usually something like Encoding.UTF8.GetBytes and then copy that buffer into the rented buffer should work but in my case there are compile time errors.
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.Convert(message, buffer.Memory, true, out _, out _, out _); // no such overload
var seq = new OwnedMemorySequence<byte>();
seq.Append(buffer);
Code
public sealed class OwnedMemorySequence<T> : IDisposable
{
private readonly CollectionDisposable _disposable = new();
private readonly MemorySequence<T> _sequence = new();
public ReadOnlySequence<T> ReadOnlySequence => _sequence.ReadOnlySequence;
public void Dispose()
{
_disposable.Dispose();
}
public OwnedMemorySequence<T> Append(IMemoryOwner<T> memoryOwner)
{
_disposable.Add(memoryOwner);
_sequence.Append(memoryOwner.Memory);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _sequence.CreateReadOnlySequence(firstBufferStartIndex, lastBufferEndIndex);
}
}
public sealed class MemorySequence<T>
{
private MemorySegment? _head;
private MemorySegment? _tail;
public ReadOnlySequence<T> ReadOnlySequence => CreateReadOnlySequence(0, _tail?.Memory.Length ?? 0);
public MemorySequence<T> Append(ReadOnlyMemory<T> buffer)
{
if (_tail == null)
_head = _tail = new MemorySegment(buffer, 0);
else
_tail = _tail.Append(buffer);
return this;
}
public ReadOnlySequence<T> CreateReadOnlySequence(int firstBufferStartIndex, int lastBufferEndIndex)
{
return _tail == null ? new ReadOnlySequence<T>(Array.Empty<T>()) : new ReadOnlySequence<T>(_head!, firstBufferStartIndex, _tail, lastBufferEndIndex);
}
private sealed class MemorySegment : ReadOnlySequenceSegment<T>
{
public MemorySegment(ReadOnlyMemory<T> memory, long runningIndex)
{
Memory = memory;
RunningIndex = runningIndex;
}
public MemorySegment Append(ReadOnlyMemory<T> nextMemory)
{
var next = new MemorySegment(nextMemory, RunningIndex + Memory.Length);
Next = next;
return next;
}
}
}
public static class MemoryOwnerExtensions
{
/// <summary>
/// Rent a buffer from a pool with an exact length.
/// </summary>
/// <param name="pool">The <see cref="MemoryPool{T}" /> instance.</param>
/// <param name="exactBufferSize">The exact size of the buffer.</param>
public static IMemoryOwner<T> RentExact<T>(this MemoryPool<T> pool, int exactBufferSize)
{
if (pool == null) throw new ArgumentNullException(nameof(pool));
var rented = pool.Rent(exactBufferSize);
if (exactBufferSize == rented.Memory.Length)
return rented;
return new SliceOwner<T>(rented, 0, exactBufferSize);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
/// <param name="length">The length of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start, int length)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0 && length == owner.Memory.Length)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
if ((uint)length > (uint)(owner.Memory.Length - start)) throw new ArgumentOutOfRangeException(nameof(length));
return new SliceOwner<T>(owner, start, length);
}
/// <summary>
/// Wrap an existing <see cref="IMemoryOwner{T}" /> instance in a lightweight manner, but allow
/// the <see cref="IMemoryOwner{T}.Memory" /> member to have a different length.
/// </summary>
/// <param name="owner">The original instance.</param>
/// <param name="start">The starting offset of the slice.</param>
public static IMemoryOwner<T> Slice<T>(this IMemoryOwner<T> owner, int start)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
if (start == 0)
return owner;
if ((uint)start >= (uint)owner.Memory.Length) throw new ArgumentOutOfRangeException(nameof(start));
return new SliceOwner<T>(owner, start);
}
private sealed class SliceOwner<T> : IMemoryOwner<T>
{
private IMemoryOwner<T> _owner;
public SliceOwner(IMemoryOwner<T> owner, int start, int length)
{
_owner = owner;
Memory = _owner.Memory.Slice(start, length);
}
public SliceOwner(IMemoryOwner<T> owner, int start)
{
_owner = owner;
Memory = _owner.Memory.Slice(start);
}
public Memory<T> Memory { get; private set; }
public void Dispose()
{
if (_owner != null)
{
_owner.Dispose();
_owner = null;
}
Memory = default;
}
}
}
Indeed, no such overload exists. Where did you look in the documentation to set that argument?
Encoding.Convert Method
Encoder have a similar method.
Encoder.Convert Method
EncodingExtensions.Convert Method
using System;
using System.Buffers;
using System.Text;
public class Program
{
public static void Main()
{
var message = "Hello";
var buffer = MemoryPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(message));
Encoding.UTF8.GetEncoder().Convert(message, buffer.Memory.Span, true, out _, out _, out _);
Console.WriteLine(Encoding.UTF8.GetString(buffer.Memory.Span));
}
}

SQLite Implementation in VS 2019

I'm still really new to coding and trying to make my first WPF application. I have been trying to implement sqlite for the past like 3 days now.
I am using VS 2019. I have downloaded the SQLite Toolbox and am following the instructions here - https://github.com/ErikEJ/SqlCeToolbox/wiki/EF6-workflow-with-SQLite-DDEX-provider. I did a full installation. Was I supposed to install it in my project directory? Because now I just have a bunch of files and nothing seems to have changed in Studio. I tried using Install.exe, but it returned a "confirm option not enabled" error. Looking at a similar question, I tried putting the files in an external folder in my project, and then installed the System.Data.SQLite.EF6.dll to my GAC using the VS Dev Console. The toolbox doesn't see any changes, and does not recognize the dll and I'm having a hard time finding reliable information for my version. Thanks for any help getting pointed in the right direction!
I'm not sure why you mention toolbox as far as I'm aware you access the SQLite functionality programmatically.
The NuGet packages that I recently used for a Xamarin project (SQLite-net-pcl by Frank Krueger and supporting libraries) allowed me to use pretty simple object mapping without recourse to SQL like strings.
I use a lot of interfaces in my code, but here's my all access database class
:
public class AllAccessDataTableBaseSqLite<T> : IDataAccessRead<T>, IDataAccessWrite<T>,IDataAccessExpressionSearch<T>, IDataAccessDelete<T> where T: IDataRecord, new()
{
//Note that this static value will only apply to those classes based on the same generic type e.g. all DataTableBase<User> instances etc.
public static SQLiteAsyncConnection DBConnection;
/// <summary>
/// Lock object to prevent multi-thread interruption of code segment.
/// </summary>
public static readonly object CollisionLock = new object();
/// <summary>
/// Constructor
/// </summary>
public AllAccessDataTableBaseSqLite()
{
lock (CollisionLock)
{
if (DBConnection != null)
{
DBConnection.CreateTableAsync<T>().Wait();
return;
}
try
{
string directory;
if (DeviceInfo.Platform != DevicePlatform.Unknown)
{
directory = FileSystem.AppDataDirectory;
}
else
{
directory = "DataStore";
var directoryInfo = Directory.CreateDirectory(directory);
directory = directoryInfo.FullName;
}
var path = Path.Combine(directory, $"{typeof(T).Name}.db");
if (!File.Exists(path))
{
using var fileStream = File.Create(path);
fileStream.Close();
}
DBConnection = new SQLiteAsyncConnection(path);
DBConnection.CreateTableAsync<T>().Wait();
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
}
}
}
}
/// <summary>
/// Create the data table
/// </summary>
/// <returns></returns>
public async Task<CreateTableResult> CreateTableAsync()
{
if (DBConnection != null)
{
return await DBConnection.CreateTableAsync<T>();
}
return CreateTableResult.Migrated;
}
/// <summary>
/// Create a new record entry
/// </summary>
/// <param name="entity">Data entity to enter</param>
/// <param name="user">Current User information</param>
/// <returns>New entry record if successful</returns>
public async Task<T> CreateAsync(T entity, IUserRecord user)
{
if (entity == null)
{
return default(T);
}
if (DBConnection == null)
{
return default(T);
}
entity.CreatedDate = DateTime.UtcNow;
entity.CreatedByUserId = user.Id;
entity.Id = 0;
try
{
await DBConnection.InsertAsync(entity);
}
catch (SQLiteException e)
{
if (e.Message == "Constraint")
{
throw new InvalidConstraintException(e.Message, e.InnerException);
}
}
var result = entity;
return result;
}
/// <summary>
/// Update a collection of new entities of type T to the data table.
/// All entities should be present within the data table
/// </summary>
/// <param name="entityList">Entity collection</param>
/// <param name="user">user making the change</param>
/// <returns>ID of entities successfully updated or added</returns>
public async Task<int> UpdateAllAsync(IEnumerable<T> entityList, IUserRecord user)
{
var result = 0;
foreach (var t in entityList)
{
if (null != await UpdateAsync(t, user))
{
result++ ;
}
}
return result;
}
/// <summary>
/// Obtain the data record with the given Id
/// </summary>
/// <param name="id">Id value to select the record by</param>
/// <returns>A valid record if found otherwise null</returns>
public async Task<T> GetById(int id)
{
if (DBConnection == null)
{
return default(T);
}
return await DBConnection.Table<T>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
/// <summary>
/// This function returns all database entries that are not marked deleted or changed
/// Warning: The data set may be very large
/// </summary>
/// <returns>A list of entries</returns>
public async Task<List<T>> GetAll()
{
if (DBConnection != null)
{
return await DBConnection.Table<T>().Where(x=>x.ChangedDate==default && x.DeletedDate==default)
.ToListAsync();
}
return new List<T>();
}
/// <inheritdoc />
public async Task<List<T>> GetAllHistoric() => await DBConnection.Table<T>().ToListAsync();
/// <summary>
/// This function is used to update the supplied record entry within the database.
/// If the supplied record does not have a non-zero value Id field it is assumed to be a
/// new record to be inserted into the database.
/// </summary>
/// <param name="entity">Record to update</param>
/// <param name="user">User performing the action</param>
/// <returns></returns>
public async Task<T> UpdateAsync(T entity, IUserRecord user)
{
if (DBConnection == null)
{
return default(T);
}
if (entity == null)
{
return default(T);
}
var newRecord = (T) ((entity) as BaseRecord<T>)?.Clone();
if (null == newRecord)
{
return default(T);
}
//if Id is zero assume that the record is new and to be added
if (newRecord.Id == 0)
{
if (user != null)
{
newRecord.CreatedByUserId = user.Id;
}
newRecord.CreatedDate = DateTime.UtcNow;
newRecord.Id = await DBConnection.InsertAsync(newRecord);
return newRecord;
}
// Id is not zero and thus a new record should be created linked to the old record.
var oldRecord = await GetById(newRecord.Id);
oldRecord.ChangedDate = DateTime.UtcNow;
if (user != null)
{
oldRecord.ChangedByUserId = user.Id;
}
try
{
var result = await DBConnection.UpdateAsync(oldRecord);
}
catch (Exception e)
{
Debug.WriteLine($"UpdateAsync {e.Message}");
}
newRecord.PreviousRecordId = oldRecord.Id;
newRecord.Id = 0;
return await CreateAsync(newRecord, user);
}
/// <inheritdoc />
public async Task<int> DeleteAsync(T entity)
{
if (DBConnection == null)
{
return -1;
}
return await DBConnection.DeleteAsync(entity);
}
/// <inheritdoc />
public async Task DeleteAll()
{
await DBConnection.DropTableAsync<T>();
await CreateTableAsync();
}
/// <inheritdoc />
public async Task<PagedResult<T>> GetAllPagedResult(int recordId, uint maxResults = 100)
{
if (DBConnection == null)
{
return null;
}
List<T> list;
if (maxResults == 0)
{
list = await GetAll();
}
else
{
list = await DBConnection.Table<T>().Where(x => (x.Id >= recordId && x.ChangedDate == default && x.DeletedDate == default)).ToListAsync();
if (list.Count() > maxResults)
{
list = list.GetRange(0, (int) maxResults);
}
}
return new PagedResult<T>(list, list.Count());
}
/// <inheritdoc />
public async Task<IEnumerable<T>> FindAsyncOrdered<TValue>(Expression<Func<T, bool>> predicate = null,
Expression<Func<T, TValue>> orderBy = null)
{
var query = DBConnection.Table<T>();
if (predicate != null)
{
query = query.Where(predicate);
}
if (orderBy != null)
{
query = query.OrderBy<TValue>(orderBy);
}
return await query.ToListAsync();
}
/// <inheritdoc />
public async Task<T> FindFirst(Expression<Func<T, bool>> predicate) => await DBConnection.FindAsync(predicate);
}
I'm using data classes based upon:
public interface IDataRecord
{
/// <summary>
/// Identifier for record
/// </summary>
int Id { get; set; }
/// <summary>
/// Link to previous version of record
/// </summary>
int PreviousRecordId { get; set; }
/// <summary>
/// User Identity that made the change
/// </summary>
int ChangedByUserId { get; set; }
/// <summary>
/// Date when the data record was last changed
/// </summary>
DateTime ChangedDate { get; set; }
/// <summary>
/// Identity of User that deleted the record
/// </summary>
int DeletedByUserId { get; set; }
/// <summary>
/// Date when the data record was deleted
/// </summary>
DateTime DeletedDate { get; set; }
/// <summary>
/// Identity of User that created the record
/// </summary>
int CreatedByUserId { get; set; }
/// <summary>
/// Date when the data record was added
/// </summary>
DateTime CreatedDate { get; set; }
object Clone();
}
Obviously you don't have to use this, but put simply for my application implementation each type of data record is stored in its own data file (thus 1 table per file) and this is created at the beginning in the constructor.
The SQLite db connection is created using the data file path.
Table is created using the dbconnection
edit
I've had a closer look at your code.
Points to note are:
You don't appear to be creating a table.
Access to non-app folders is restricted if you chose to create a UWP rather than base WPF project - be aware of folder access permissions when running apps especially in release mode.

How to reduce my redundant code, creating generic methods?

I have a code to insert and update entities, but the logic are very similar: instance a controller, validate de request, if error, resturns Failed, else execute the operation.
/// <summary>
/// Method Add with similar code in Update method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Add(PersonInsertRequest item)
{
var result = new PersonResponse();
var controller = new PersonController(classmates);
result.Messages = controller.ValidateInsert(item);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = controller.ExecuteInsert(item);
}
return result;
}
/// <summary>
/// Method Update with similar code in Add method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Update(PersonUpdateRequest item)
{
var result = new PersonResponse();
var controller = new PersonController(classmates);
result.Messages = controller.ValidateUpdate(item);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = controller.ExecuteUpdate(item);
}
return result;
}
-
I have tried to use delegates, but I can't use them, because I cannot assign a delegate to controller.ValidateInsert(item);
public class BaseLogic
{
public delegate List<Message> Validator(BaseRequest request);
public delegate BaseResponse Executor(BaseRequest request);
public BaseResponse Execute(BaseRequest request, Validator funcValidator, Executor funcExecutor)
{
var result = new BaseResponse();
result.Messages = funcValidator(request);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = funcExecutor(request);
}
return result;
}
}
I want to reduce Add method and Update method in another more generic.
using System;
using System.Collections.Generic;
using System.Linq;
class Test
{
private object classmates;
public PersonResponse Add(PersonInsertRequest item)
{
var controller = new PersonController(classmates);
return ValidateAndExecute(() => controller.ValidateInsert(item),
() => controller.ExecuteInsert(item));
}
public PersonResponse Update(PersonUpdateRequest item)
{
var controller = new PersonController(classmates);
return ValidateAndExecute(() => controller.ValidateUpdate(item),
() => controller.ExecuteUpdate(item));
}
private PersonResponse ValidateAndExecute(Func<IEnumerable<string>> validator,
Func<PersonResponse> execute)
{
var result = new PersonResponse();
result.Messages = validator();
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = execute();
}
return result;
}
}
With my generic method in my base class, I can refactorize my methods
/// <summary>
/// Method Add with similar code in Update method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Add(PersonInsertRequest item)
{
var controller = new PersonController(classmates);
Validator myValidator = request => controller.ValidateInsert((PersonInsertRequest)request);
Executor myExecutor = request => controller.ExecuteInsert((PersonInsertRequest)request);
var result = Execute(item, myValidator, myExecutor);
return result as PersonResponse;
}
/// <summary>
/// Method Update with similar code in Add method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Update(PersonUpdateRequest item)
{
var controller = new PersonController(classmates);
Validator myValidator = request => controller.ValidateUpdate((PersonUpdateRequest)request);
Executor myExecutor = request => controller.ExecuteUpdate((PersonUpdateRequest)request);
var result = Execute(item, myValidator, myExecutor);
return result as PersonResponse;
}

Singleton dictionary is not being singleton

I have a dictionary in a singleton class. I am saving there the pair , every time I access to that dictionary from the method that is creating the token it shows all the credentials that I've stored there.
But when I access from another class in another project of the solutions it displays the dictionary empty. Can anybody tell me why this happens?
This is the class that manage the dictionary:
public class UserAccessToken
{
public Dictionary<string, string> UserDictionary { get; set; }
private static UserAccessToken _instance;
private UserAccessToken() { }
public static UserAccessToken Instance
{
get
{
if (_instance == null)
_instance = new UserAccessToken
{
UserDictionary = new Dictionary<string, string>()
};
return _instance;
}
}
}
This is the method that insert the key,value pair in the dictionary:
public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
{
var accessToken = context.AccessToken;
if (context.Properties.Dictionary.ContainsKey("userName"))
{
var username = context.Properties.Dictionary["userName"];
// If I access here multiple times the singleton works
UserAccessToken.Instance.UserDictionary[username] = accessToken;
}
return Task.FromResult<object>(null);
}
This is the method where I access the dictionary, from here I can see that it's empty:
private bool IsTokenValid(HttpContextBase httpContext)
{
var username = httpContext.User.Identity.Name;
var userTokens = UserAccessToken.Instance.UserDictionary;
var tokenToAccess = httpContext.Request.Headers["Authorization"];
tokenToAccess = tokenToAccess.Replace("Bearer ", "");
if (userTokens.ContainsKey(username))
{
var token = userTokens[username];
if (token == tokenToAccess) return true;
}
return true;
}
I already solved my problem, but I'll let my solution here in case could be useful for somebody.
The problem is that if you are running two different projects, that will mean two different process, so, what I wanted to do is pretty impossible. I used Redis for this and it is working well.
This is an example of Redis use:
public class CallManagerCache : ICallManagerMethods{
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer
.Connect(CloudConfigurationManager.GetSetting("RedisConnectionString")));
public static ConnectionMultiplexer cacheConnection
{
get
{
return lazyConnection.Value;
}
}
/// <summary>
/// Here you save the value in cache, you get the connection, then StringSetAsync is in charge of saving the value
/// </summary>
/// <param name="name"></param>
/// <param name="template"></param>
public async Task UpdateCallInstance(int id, byte[] data, bool instanceForCallback = false, TimeSpan? timespan = null)
{
var cache = cacheConnection.GetDatabase();
await cache.StringSetAsync(instanceForCallback ? $"Call_{id}" : id.ToString(), data, timespan ?? new TimeSpan(0, 0, 15, 0));
}
/// <summary>
/// Here you get the value in cache, you get the connection, then StringGetAsync is in charge of getting the value
/// </summary>
/// <param name="name"></param>
/// <param name="template"></param>
public async Task<CallInstance> GetById(int id, bool isForCallback)
{
var cache = cacheConnection.GetDatabase();
var callInstance = new CallInstance
{
Id = id,
InstanceData = await cache.StringGetAsync(isForCallback ? $"Call_{id}" : id.ToString())
};
return callInstance;
}
}

Entity Framework - System.StackOverflowException

I am new to entity framework and have hit an issue trying to insert new items into a lookup table.
The error is -
"An unhandled exception of type System.StackOverflowException
occurred in mscorlib.dll"
It is thrown in the final code block below where public DIEMEntities() is called.
It occurs whenever I add a new item, I can update items ok.
Any help would be appreciated.
The code is -
protected void OnSave(object sender, EventArgs e)
{
ArrayList validationErrors = new ArrayList();
ContactTypeEO contactType = new ContactTypeEO();
if (uxID.Value.Length > 0)
{
//Updating
contactType.Id = int.Parse(uxID.Value);
}
contactType.Name = uxName.Text;
contactType.ExpressionValidator = uxExpression.Text;
contactType.Save(ref validationErrors);
if (validationErrors.Count > 0)
{
ShowValidationMessages(validationErrors);
}
else
{
this.RefreshUI();
}
}
public bool Save(ref ArrayList validationErrors)
{
ValidateSave(ref validationErrors);
if (validationErrors.Count == 0)
{
if (Id == 0)
{
ContactTypeData.Insert(Name, ExpressionValidator);
}
else
{
ContactTypeData.Update(Id, Name, ExpressionValidator);
}
return true;
}
else
{
return false;
}
}
/// <summary>
/// Inserts the new Contact Type.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="validator">The validator.</param>
public static void Insert(string name, string validator)
{
using (DIEMEntities diemEntities = new DIEMEntities())
{
Insert(name, validator);
}
}
/// <summary>
/// Inserts the new Contact Type.
/// </summary>
/// <param name="diemEntities">The DIEM Entities.</param>
/// <param name="name">The name.</param>
/// <param name="validator">The validator.</param>
public static void Insert(DIEMEntities diemEntities, string name, string validator)
{
diemEntities.usp_ContactTypes_Insert(name, validator);
}
public partial class DIEMEntities : DbContext
{
public DIEMEntities()
: base("name=DIEMEntities")
{
}
... OTHER CODE}
You have a recursive loop here:
public static void Insert(string name, string validator)
{
using (DIEMEntities diemEntities = new DIEMEntities())
{
Insert(name, validator);
}
}
This will execute continuously until you run out of memory.
I believe you're intention is to do this:
public static void Insert(string name, string validator)
{
using (DIEMEntities diemEntities = new DIEMEntities())
{
Insert(diemEntities, name, validator);
}
}

Categories