Servicestack automap update endpoints - servicestack

We are using ServiceStack QueryDb to expose certain business objects for auto-querying, and it is working great.
[Route("/catalog/customers")]
[Authenticate]
public class QueryCustomers : QueryDb<ServiceModel.Catalog.Customer> { }
We'd like to implement some sort of UpdateDb that auto-maps authenticated POST, PUT and DELETE requests to insert, update and delete auto-mapped predefined OrmLite business objects, but don't see any examples on the web. Ideally, we could create an endpoint as simple as:
[Route("/edits/customers")]
[Authenticate]
public class UpdateCustomers : UpdateDb<ServiceModel.Catalog.Customer> { }
I'd prefer to not have to roll our own if this has already been done somewhere in the ServiceStack library or elsewhere... Is this something that ServiceStack already supports, or are we on our own in developing this UpdateDb utility?...

This would require a CRUD version of AutoQuery which doesn't exist yet so you would need to implement your Update services as normal.

Haven't done a lot of testing, but it looks like the UpdateDb will involve one tweak against the QueryDb implementation -
public long CreateUpdate<From>(IUpdateDb<From> dto, Dictionary<string, string> dynamicParams, IRequest req = null)
{
long result;
var db = GetDb<From>(req);
var body = req.GetRawBody();
var jsonObject = JsonObject.Parse(body);
var obj = jsonObject.ConvertTo<From>();
var id = (obj as IHasId<int>)?.Id;
if (id == null)
throw new Exception("Cannot update without identity field defined");
if (req.Verb == "DELETE")
{
result = db.DeleteById<From>(id);
}
else if (req.Verb == "POST")
{
db.InsertAll(new[] { obj });
result = ((IHasId<int>)obj).Id;
}
else
{
result = db.UpdateOnly(obj,
jsonObject.Keys.ToArray(),
u => ((IHasId<int>)u).Id == id);
}
return result;
}

Related

How to programmatically assign roles and permissions to services and/or RequestDTOs

Statically I set access to my services like so:
[Authenticate]
public class AppUserService : Service
{
[RequiredRole("Administrator")]
public object Post(CreateAppUser request)
{
//.....
}
}
How can I do this programmatically?
I will let the user create roles using a GUI. Then I will present a list of available methods, e.g. by providing the methods using improved code like:
var appHost = HostContext.AppHost;
var restPaths = appHost.RestPaths;
foreach (var restPath in restPaths)
{
var reqType = restPath.RequestType;
string verbs = string.Empty;
if (restPath.Verbs != null)
{
var counter = 0;
foreach (var verb in restPath.Verbs)
{
if (counter > 0) verbs += ", ";
verbs += verb;
counter++;
}
}
Debug.WriteLine($"Path: {restPath.Path} | Verbs: {verbs} | Name: {reqType.Name} FullName: {reqType.FullName}");
}
The code above outputs something like
Path: /appusers | Verbs: POST | Name: CreateAppUser FullName: MyServer.ServiceModel.DTOs.Request.CreateAppUser
So I could show in my UI the Name property of the RequestType and let him define, what roles are allowed to call this method. So the user may create a role called 'User Management' and allow members of this role to execute CreateAppUser.
Using annotations I would write
[RequiredRole("Administrator", "User Management")]
public object Post(CreateAppUser request)
{ .... }
Is this anyhow possible in C# code?
ServiceStack does have a way to dynamically Add Attributes at runtime, e.g:
typeof(CreateAppUser)
.AddAttributes(new RequiredRoleAttribute("Administrator", "User Management"));
Which is an alternative to declaring attributes statically, but it's still not a solution for a data-driven authorization system.
But you could add your own custom Authorization logic in addition to ServiceStack's built-in attributes by validating it in your Service:
public ICustomAuth CustomAuth { get; set; }
public object Post(CreateAppUser request)
{
var session = base.GetSession();
var requiresRoles = CustomAuth.GetRequiredRoles(request.GetType());
var hasAllRoles = requiresRoles.All(r =>
session.HasRole(r, base.AuthRepository))
if (!hasAllRoles)
throw new UnauthorizedAccessException("Requires all roles");
}
If you do this a lot you will want to refactor the custom validation logic into a single reusable method, or if you prefer into a custom RequestFilter attribute.

Azure App Service - Update object from table controller

In the Azure app service mobile backend service, REST API requests are handled by TableController implementation. These methods can be invoked by using corresponding methods available in client SDKs. So, i can query for a particular entity and update its status from the client side.
But how to invoke them in the server side or within the same controller? For example, if I want to query for a particular todoItem and update its status from some custom method here like
Use LookUp(id) to get the item
Update the status
Use UpdateAsync(id, item)
Here I don't know how to create a Delta object of TodoItem to call UpdateAsync(id, patch) method.
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
initrackerserviceContext context = new initrackerserviceContext();
DomainManager = new EntityDomainManager<TodoItem>(context, Request);
}
// GET tables/TodoItem
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
// GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<TodoItem> GetTodoItem(string id)
{
return Lookup(id);
}
// PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TodoItem
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
}
Just use the standard Entity Framework mechanisms. For instance, to find and update a record with a status, you can just use the context:
var item = await context.TodoItems.Where(i => i.Id.Equals(myId)).FirstOrDefaultAsync<TodoItem>();
if (item != null) {
item.Complete = true;
context.Entry(item).State = EntityState.Modified;
await context.SaveChangesAsync();
}
My EF coding is not the greatest ad-hoc, but you should get the idea. Just do the Entity Framework thing.
It's better to use TableController.ReplaceAsync() method that is already implemented for us here in the source code of EntityDomainManager.
var item = Lookup(item.Id).Queryable.FirstOrDefault();
if (item != null)
{
item.Complete = true;
item = await ReplaceAsync(item.Id, item);
}
The ReplaceAsync() method correctly handles the exceptions, so I would not recommend working directly with the EF context.

dynamics crm plugin delete entity during update message

Is it possible to delete entity while same is still in plugin update transaction?
It seems following code is not working. I need to delete entity when its get updated and some other circumstances
Something like:
protected void ExecutePosAnnotationtUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
if (localContext.PluginExecutionContext.Depth > 1) return;
Entity postEntityImage = null;
if (localContext.PluginExecutionContext.PostEntityImages.Contains("PostImage"))
{
if (localContext.PluginExecutionContext.PostEntityImages["PostImage"] != null)
{
postEntityImage = localContext.PluginExecutionContext.PostEntityImages["PostImage"];
}
}
Entity preEntityImage = null;
if (localContext.PluginExecutionContext.PreEntityImages.Contains("PreImage"))
{
if (localContext.PluginExecutionContext.PreEntityImages["PreImage"] != null)
{
preEntityImage = localContext.PluginExecutionContext.PreEntityImages["PreImage"];
}
}
if ((bool)postEntityImage.Attributes["isdocument"])
{
if ( some condition )
localContext.OrganizationService.Delete(postEntityImage.LogicalName, postEntityImage.Id);
}
}
`
Since you're updating, the record is there in Target.
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
var target = context.InputParameters["Target"] as Entity;
var condition = /* whatever */
if(condition)
{
service.Delete(target.LogicalName, target.Id);
}
}
Works as expected when attached to Update message, Post-Operation, Asynchronous. Works inside the Sandbox, also.
Records will not disappear at once, it takes some time (~20 seconds on my on-premise playground). If you make it Synchronous it will still work but alerts are going to come up because data disappears while being handled by the CRM during the update.

SharePoint oData API Only Returns 1000 Records

I am trying to query a SharePoint 2013 list using the Rest API for all items in the list. The problem is it only returns 1000 records max and I need to get all of the records. I am using the oData v4 API and auto generated service references for the site.
I figured it out: I am including the question and answer here in case anyone else needs it.
I created an extension method called SelectAll() that returns all of the records for a given query.
public static List<T> SelectAll<T>(this DataServiceContext dataContext, IQueryable<T> query)
{
var list = new List<T>();
DataServiceQueryContinuation<T> token = null;
var response = ((DataServiceQuery)query).Execute() as QueryOperationResponse<T>;
do
{
if (token != null)
{
response = dataContext.Execute(token);
}
list.AddRange(response);
} while ((token = response.GetContinuation()) != null);
return list;
}
You use it by calling dataContext.SelectAll(query);
I had the same problem, and wanted it to be a generic solution without providing the query. I do use the EntitySetAttribute to determine the listname.
public static List<T> GetAlltems<T>(this DataServiceContext context)
{
return context.GetAlltems<T>(null);
}
public static List<T> GetAlltems<T>(this DataServiceContext context, IQueryable<T> queryable)
{
List<T> allItems = new List<T>();
DataServiceQueryContinuation<T> token = null;
EntitySetAttribute attr = (EntitySetAttribute)typeof(T).GetCustomAttributes(typeof(EntitySetAttribute), false).First();
// Execute the query for all customers and get the response object.
DataServiceQuery<T> query = null;
if (queryable == null)
{
query = context.CreateQuery<T>(attr.EntitySet);
}
else
{
query = (DataServiceQuery<T>) queryable;
}
QueryOperationResponse<T> response = query.Execute() as QueryOperationResponse<T>;
// With a paged response from the service, use a do...while loop
// to enumerate the results before getting the next link.
do
{
// If nextLink is not null, then there is a new page to load.
if (token != null)
{
// Load the new page from the next link URI.
response = context.Execute<T>(token);
}
allItems.AddRange(response);
}
// Get the next link, and continue while there is a next link.
while ((token = response.GetContinuation()) != null);
return allItems;
}

Attempting ValidationAttribute in MVC4 that is asynchronous using Async, Task and Await

I am attempting to write a Validation attribute in MVC4.
The purpose is to check for the existence of an application reference (just a string that represents a key I wish to prevent a duplicate for).
My data is accessed via WebAPI and because I am using 4.5 I wish to make this asynchronous if possible.
I am perhaps not making the best or appropriate usage of async and await but I would like to know how to call my async method from the overridden IsValid method of the inherited Validation class.
public class UniqueApplicationReferenceAttribute : ValidationAttribute
{
public UniqueApplicationReferenceAttribute() : base(() => "The {0} already exists") { }
public int? ApplicationCount { get; set; }
public override bool IsValid(object value)
{
var myTask = GetApplicationRefCountAsync();
myTask.Wait();
this.ApplicationCount = this.ApplicationCount ?? 0;
if (ApplicationCount > 0)
{
return true;
}
else
{
return false;
}
}
public async Task GetApplicationRefCountAsync()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:11111/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var apps = client.GetStringAsync("api/dataapplications");
await Task.WhenAll(apps);
var appList = apps.Result;
this.ApplicationCount = appList.Count();// apps.Count();
}
}
Many thanks,
Dan.
I recommend that you call your WebAPI methods synchronously. ValidationAttribute does not support asynchronous implementations natively, so any synchronous-over-asynchronous code you'll write is just going to be a hack and not actually provide any benefit as compared to the synchronous version.
I'm not able to test this in full, but you should be able to do something like this:
public bool IsValid(object value)
{
var appCount = GetApplicationRefCountAsync().Result;
return appCount > 0;
}
public async Task<int> GetApplicationRefCountAsync()
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:11111/");
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return await client.GetStringAsync("api/dataapplications")
.ContinueWith(r => Convert.ToInt32(r))
.ConfigureAwait(false);
}
Be careful about using async/await methods in an ASP.NET thread. It's easy to create deadlocks.

Resources