Using DocumentClient.ReadDocumentAsync when you do not know the partitionkey - c#

I have a situation where I need to retrieve a particular document but I do not know it's PartitionKey.
The method looks like this:
public async Task<T> GetItemAsyncNoGroupId(string id)
{
try
{
Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id),
new RequestOptions() { PartitionKey = new PartitionKey(Undefined.Value) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
I passed in the Undefined.Value to the PartitionKey object and that didn't work. I also didn't pass any PartionKey object into the ReadDocumentAsync method and that didn't work. I always get 'No Content' passed back. Any suggestions on how I can get this to work?

You need to use a cross partition query. Read about it here.

Related

Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection

i have table for set user Access Level in Tabel .
this is my Access :
public Guid RoleId { get; set ; }
public string Access { get ; set ; }
i want when the AccessLevel is changed it must changed the SecurityStamp in Role table .
public async Task<OperationResult<string>> Handle(SetAccessLevelCommand request, CancellationToken cancellationToken)
{
var result = await unitOfWork.RoleRepository.AccessLevelRepository.SetAccess(new AccessLevelDto { RoleId = request.RoleId, Access = request.AccessList });
if (result.Success)
{
try
{
try
{
var findRole = await unitOfWork.RoleRepository.GetRoleByIdAsync(request.RoleId, cancellationToken);
findRole.Result.UpdateSecurityStamp();
if (findRole.Result != null)
{
unitOfWork.RoleRepository.Update(findRole.Result, cancellationToken);
unitOfWork.CommitSaveChange();
return OperationResult<string>.BuildSuccessResult("Add Success");
}
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex.Message);
}
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex.Message);
}
}
return OperationResult<string>.BuildFailure(result.ErrorMessage);
}
i write this code for doing this work .
this is the SetAccess :
public async Task<OperationResult<string>> SetAccess(AccessLevelDto accessLevels)
{
try
{
var currentRoleAccessValue = GetAccessLevels(accessLevels.RoleId);
var currentAccess = currentRoleAccessValue.Select(x => x.Access).ToList();
var newAccess = accessLevels.Access.Except(currentAccess).ToList();
if (newAccess != null)
{
foreach (var item in newAccess)
{
context.Add(new AccessLevel
{
Access = item,
RoleId = accessLevels.RoleId
});
}
}
var removeItems = currentAccess.Except(accessLevels.Access).ToList();
if (removeItems != null)
{
foreach (var item in removeItems)
{
var accClaim = currentRoleAccessValue.SingleOrDefault(x => x.Access == item);
if (accClaim != null)
{
context.Remove(accClaim);
}
}
}
return OperationResult<string>.BuildSuccessResult("SuccessAdd");
}
catch (Exception ex)
{
return OperationResult<string>.BuildFailure(ex);
}
}
this is code for change State of entity and it's worked fine and when i call the CommitSaveChange() it worked fine . but when i add the RoleUpdate commands :
var findRole = await unitOfWork.RoleRepository.GetRoleByIdAsync(request.RoleId, cancellationToken);
findRole.Result.UpdateSecurityStamp();
if (findRole.Result != null)
{
unitOfWork.RoleRepository.Update(findRole.Result, cancellationToken);
}
and then call the unitOfWork.CommitSaveChange() it show me this error :
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'FilmstanContext'.
whats the problem ? how can i solve this problem ????
When I have seen this type of issue in the past, it has usually been due to either a) missing await commands or b) async methods with a void return type. In my case, it was related to Entity Framework. Just in case it helps. Cannot access a disposed object
A related observation, I would think your call to CommitSaveChange should be asynchronous. This probably writes data to some type of data store. If reading 'GetRoleById' is async, I would think writing should also be async. Just my 2 cents.

Reducing code duplication with Microsoft Graph Client Library

I'm working on a class responsible for communicating with O365 using the Microsoft Graph Client Library. In each method, the call to NextPageRequest.GetAsync() is on a different type which also returns a different type, but otherwise the pagination logic is identical:
public async Task<List<Microsoft.Graph.User>> FindAllUsers()
{
var usersFound = new List<Microsoft.Graph.User>();
var usersPage = await GraphClient.Users.Request().GetAsync();
usersFound.AddRange(usersPage);
while (usersPage.NextPageRequest != null)
{
usersPage = await usersPage.NextPageRequest.GetAsync();
usersFound.AddRange(usersPage);
}
return usersFound;
}
public async Task<List<Microsoft.Graph.Group>> FindAllGroups()
{
var groupsFound = new List<Microsoft.Graph.Group>();
var groupsPage = await GraphClient.Groups.Request().GetAsync();
groupsFound.AddRange(groupsPage);
while (groupsPage.NextPageRequest != null)
{
groupsPage = await groupsPage.NextPageRequest.GetAsync();
groupsFound.AddRange(groupsPage);
}
return groupsFound;
}
public async Task<List<Microsoft.Graph.User>> FindGroupMembers(string groupId)
{
var usersFound = new List<Microsoft.Graph.User>();
var membersPage = await GraphClient.Groups[groupId].Members.Request().GetAsync();
usersFound.AddRange(membersPage.Where(d => d.ODataType.Equals("#microsoft.graph.user")).Cast<Microsoft.Graph.User>());
while (membersPage.NextPageRequest != null)
{
membersPage = await membersPage.NextPageRequest.GetAsync();
usersFound.AddRange((List<Microsoft.Graph.User>)membersPage);
}
return usersFound;
}
I would like to write generic method to reduce duplication, but in each of the above methods, the return type of GetAsync is a different interface that defines its own NextPageRequest property on itself. This makes it impossible to tell the generic method what specific type it will need to call NextPageRequest on so that the method can compile.
Is there a way to improve upon this, or do I just need to accept the duplicated logic for each query type I want to implement?
Thanks to Microsoft Graph API architects, it looks like we can only get rid of such sort of redundancy either by using reflection or dynamics. Since dynamics, in theory, should provide better performance, here's a version of sample code based on them:
private void ProcessAllResultPages<TResult, TItem>(IBaseRequest request,
Action<TResult> processorDelegate)
where TResult : ICollectionPage<TItem>
{
do
{
Task<TResult> task = ((dynamic)request).GetAsync();
processorDelegate(task.Result); // This will implicitly call Wait() on the task.
request = ((dynamic)task.Result).NextPageRequest;
} while (request != null);
}
Sample usage:
IGraphServiceGroupsCollectionRequest request = graphServiceClient.Groups.Request().
Filter(...).
Select(...).
Top(pageSize);
ProcessAllResultPages<IGraphServiceGroupsCollectionPage, Group>(request,
result =>
{
// Process page results here.
});
I used this to reduce duplication of code:
public async Task<List<T>> GetAllAsync<T>(IBaseRequest baseRequest)
where T : DirectoryObject
{
List<T> pagedItems = new();
try
{
var pageOfItems = await ((dynamic)baseRequest).GetAsync();
pagedItems.AddRange(pageOfItems);
while (pageOfItems.NextPageRequest != null)
{
pageOfItems = await pageOfItems.NextPageRequest.GetAsync();
pagedItems.AddRange(pageOfItems);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
return pagedItems;
}
And then use it with:
var result = await GetAllAsync<Microsoft.Graph.Group>(_graphServiceClient.Groups.Request());
var result = await GetAllAsync<Microsoft.Graph.User>(_graphServiceClient.Users.Request());

How to do async await function imports/SP EF6

I have a function imports a stored procedure, but I want to make it as async. How could I do that?
Any ideas?
public static async Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
List<ObtenerLayoutPor_Result> result = new List<ObtenerLayoutPorBanco_Result>();
try
{
using (CobranzaEntities db = new CobranzaEntities())
{
return Task.Run(() => db.ObtenerLayoutPor(96)).GetAwaiter(); //one try
result = await db.ObtenerLayoutPor(96); //second try
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return result;
}
I would do it like that:
public static Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
return Task.Run(()=>{ // no await here and function as a whole is not async
using (CobranzaEntities db = new CobranzaEntities())
{
return db.ObtenerLayoutPor(96).ToList(); // depending on your implementation, ToList may be requiered to make the actual trip to database
}
});
}
or, as suggested in comment, if you stored procedure returns IQueryable, you can simply use this code:
public static Task<List<ObtenerLayoutPor_Result>> GenerarArchivoPorBanco()
{
using (CobranzaEntities db = new CobranzaEntities())
{
return db.ObtenerLayoutPor(96).ToListAsync();
}
}
To sum up, the easiest way to make a funtion async is to wrap it in Task.Run. Then you can use it in your code:
var results = await GenerarArchivoPorBanco();

Is it possible to use method attributes to change how this method is run?

I have this method:
public object LongRunningTask()
{
return SomethingThatTakesTooLong();
}
I wrote the following code so I can transform a normal method in an async one and still get the Exception:
public async Task<object> LongRunningTaskAsync()
{
Exception ex = null;
object ret = await Task.Run(() =>
{
object r = null;
try
{
//The actual body of the method
r = SomethingThatTakesTooLong();
}
catch (Exception e)
{
ex = e;
}
return r;
});
if (ex == null)
return ret;
else
throw ex;
}
When I need to do this in several methods, I have to copy all this code and change only the middle.
Is there a way to do something like this?
[SomeAttributeThatDoesThatMagically]
public async Task<object> LongRunningTaskAsync()
{
return SomethingThatTakesTooLong();
}
Attributes are generally metadata though it is possible to define attributes that can be executed (such as security behaviours in WCF) however, something has to be looking for it first. Your attributes won't just magically run.
I suspect you might have to use a dynamic proxy.
Take a look at how WCF does things for ideas.

Can we make this method generic?

I saw this method in a sample from Xamarin, using JSON accessing a REST Server:
List<Country> countries = new List<Country>();
public Task<List<Country>> GetCountries()
{
return Task.Factory.StartNew (() => {
try {
if(countries.Count > 0)
return countries;
var request = CreateRequest ("Countries");
string response = ReadResponseText (request);
countries = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Country>> (response);
return countries;
} catch (Exception ex) {
Console.WriteLine (ex);
return new List<Country> ();
}
});
}
where "CreateRequest" and "ReadResponseText" are methods that interact with a REST Server, basically receiving a list of countries to deserialize and return in the list.
So now, I'm trying to make this method generic in order to receive the type and return a generic list of objects of the specified type, something like this:
public static Task<List<Object>> getListOfAnyObject(string requested_object, Type type)
{
return Task.Factory.StartNew (() => {
try {
var request = CreateRequest (requested_object);
string response = ReadResponseText (request);
List<Object> objects = // create a generic list based on the specified type
objects = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Object>> (response); // not sure how to handle this line
return objects;
} catch (Exception ex) {
Console.WriteLine (ex);
return ex.Message;
}
});
}
So my question is, how can I create the method above in order to use it more and less like this (casting the list to my desired type)?
List<Country> countries = (List<Country>)(List<?>) getListOfAnyObject("countries",Country.type);
Many thanks in advance!
Try something like this..
public static Task<List<T>> getListOfAnyObject<T>(string requested_object)
{
return Task.Factory.StartNew (() => {
try {
var request = CreateRequest (requested_object);
string response = ReadResponseText (request);
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>> (response); // not sure how to handle this line
} catch (Exception ex) {
Console.WriteLine (ex);
return ex.Message;
}
});
}
Called like so..
List<Country> countries = getListOfAnyObject<Country>("countries");

Categories

Resources