2sxc - Get EntityId or EntityGuid of newly created object inside custom api controller - 2sxc

For adding new entity inside my custom API I use code like this:
var tagGroup = new Dictionary<string, object>();
tagGroup.Add("Title", "Some new tagGroup name");
App.Data.Create("TagGroup", tagGroup, "WebApiUser");
This work fine if I just need to add new entity, but If I need to do more operations and in this opetarions I need to use Id or Guid of this newly created entity I don't know how to get it.
One way is to get this new entity by its title back, but If this title is not unique I don't know how?
I try with this code:
dynamic obj1 = App.Data.Create("TagGroup", tagGroup, "Web Api User");
// or
var obj2 = App.Data.Create("TagGroup", tagGroup, "Web Api User");
But get error becouse function don't return any value.. Is there any other way how to make this work?
Is posible to define guid of new entity in advance like for IsPublished?
====================
Solution 1:
var tGuid = System.Guid.NewGuid().ToString();
tagGroup.Add("EntityGuid", tGuid);
and work OK

I am OK with solution to set EntityGuid in custom api controller to get new EntityId
var tGuid = System.Guid.NewGuid();
var tagGroup = new Dictionary<string, object>();
tagGroup.Add("Title", "Some new tagGroup name");
tagGroup.Add("EntityGuid", tGuid);
App.Data.Create("TagGroup", tagGroup, "WebApiUser");
var tNewObj =AsDynamic(App.Data["TagGroup"]).Where(x=>x.EntityGuid==tGuid).First();
var tNewEntityId = tNewObj.EntityId;
// do whatewer you want with this entity..
This is my final code...

Update: 2sxc now has this functionality. .Create() now returns the newly created Entity...
In 2sxc, after an App.Data.Create(), is there a way to get the new EntityId (or Guid) or a Pointer to the new Entity?

Related

How do you store the current user as a property on a web api model

I am using a web api 2 and creating a message object to save to the database. This message object needs to have the current user stored on it as an application user type.
My code looks like this:
var UserManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var currentApplicationUser = UserManager.FindByName(currentUserName);
// I perhaps want to dispose of the user context?
// UserManager.Dispose();
globalMessage.sentBy = currentApplicationUser;
db.GlobalMessages.Add(globalMessage);
The last line is throwing the error: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Is there another way around this. Otherwise, I imagine, I could call an action which gets the current user, redirect to another action from the action with this user as an arg and then perform the update?
I worked it out:
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var sender = db.Users.Where(u => u.UserName == currentUserName).FirstOrDefault();
globalMessage.sentBy = sender;
db.GlobalMessages.Add(globalMessage);
db.SaveChanges();
The problem is you're attaching to your db context an entity (currentApplicationUser) that already is attached to another context instance that is alive too, so a solution could be to find the user using the same context, in your case it would be something like:
var UserManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var currentUser = RequestContext.Principal;
var currentUserName = currentUser.Identity.Name;
var currentApplicationUser =db.AspNetUsers.FirstOrDefault(u=>u.UserName==currentUserName);
globalMessage.sentBy = currentApplicationUser;
db.GlobalMessages.Add(globalMessage);

Get controller and action name from AuthorizationHandlerContext object

Hi I have a custom requirement handler with accepts the AuthorizationHandlerContext context parameter
When i debug, i can see that the context object contains
Context.Resources.ActionDescription.ActionName
But when writing the code i cant go beyond
Context.Resources
Seems the lower levels are not exposed. I want to get the action name and controller name that called the handler. How do i do this?
var mvcContext = context.Resource as AuthorizationFilterContext;
var descriptor = mvcContext?.ActionDescriptor as ControllerActionDescriptor;
if (descriptor != null)
{
var actionName = descriptor.ActionName;
var ctrlName = descriptor.ControllerName;
}
After upgrading to dotnet 5, the solution I was successfully using from Carsten above stopped working. The following workaround now works for me:
var routeValues = (context.Resource as HttpContext).Request.RouteValues;
var controllerName = routeValues["controller"].ToString();
var actionName = routeValues["action"].ToString();
Note this should include some null checks etc. the above is a barebones example.
Even though the question is tagged for asp.net-mvc, I wanted to add that the answer by #AdemCaglin does not work for Web API controllers. The following code works for both, API and MVC controllers:
var endpoint = context.Resource as RouteEndpoint;
var descriptor = endpoint?.Metadata?
.SingleOrDefault(md => md is ControllerActionDescriptor) as ControllerActionDescriptor;
if (descriptor == null)
throw new InvalidOperationException("Unable to retrieve current action descriptor.");
var controllerName = descriptor.ControllerName;
var actionName = descriptor.ActionName;

How to not bind the property which as default value in web api return

I have many classes , methods and I need some data which as default value should not be serialized, if this should done in return of webapi i don't need all the class to change. can anyone as a idea please share.
I have done in the application start like the following code.
But it doesn't work for me. In addition, I need to remove the properties which has default value on serialization.
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter
{
SerializerSettings = new JsonSerializerSettings()
});
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;

Alfresco can I Change properties "cmis:creationDate and cmis:lastModificationDate" Updatablity?

Hi and thanks in advance for the help
I have a problem with insertion and update documents in alfresco, So when I set a property like "cmis:creationDate or cmis:lastModificationDate", the document is created successfully but the properties that has Updatability=ReadOnly doesn't set to the new value given it's set automatically by alfresco.
Is there any solution to set Updatibility of these properties to "ReadWrite"?
I'm using Aalfresco 5.0 and openCmis 0.13 this is my code :
public void createDocument(Folder folder) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date d = sdf.parse("21/12/2012");
String name = "myNewDocument.txt";
Map<String, Object> properties = new HashMap<String, Object>();
Calendar cal = new GregorianCalendar();
cal.setTime(d);
properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document,P:cm:titled,P:cm:author");
properties.put(PropertyIds.NAME, name);
properties.put(PropertyIds.CREATION_DATE, cal);
properties.put(PropertyIds.LAST_MODIFICATION_DATE, cal);
properties.put("cm:title", "Title");
properties.put("cm:description", "Description");
properties.put("cm:author", "author");
properties.put("cmis:creationDate ", cal);
byte[] content = "Hello World!".getBytes();
InputStream stream = new ByteArrayInputStream(content);
ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(content.length), "text/plain", stream);
Document newDoc = folder.createDocument(properties, contentStream, VersioningState.MAJOR);
}
Updating the read only fields requires work on the Alfresco side. There are policies in place that prevent properties of the aspect cm:auditable from being changed.
You can update the fields in Alfresco using the NodeService API after you've disabled that policy behavior. Here's an example:
policyBehaviourFilter.disableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
// Update CreatedDate
nodeService.setProperty(node, ContentModel.PROP_CREATED, dateTime);
//Enable policy
policyBehaviourFilter.enableBehaviour(node, ContentModel.ASPECT_AUDITABLE);
You could package this into a custom webscript to allow the properties to be changed remotely.

Unit Test hitting UrlHelper extension method always fails to match route based on route name

... but the same extension method works when the application itself is executing. The UrlHelper extension method itself looks like this:
public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
{
return helper.RouteUrl("Category", new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = seoCategoryName }, "http");
}
I register that particular route like this in my SoAndSoAreaRegistration class:
context.MapRoute(
"Category",
"category/{seoCategoryName}",
new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = string.Empty }
);
... and I have dropped a breakpoint on that registration to ensure that it gets hit by the test runner, and it does.
When I run the test, I get an ArgumentException, "A route named 'Category' could not be found in the route collection. Parameter name: name".
My guess is that we do not need to specify the route name and enough route parameters (area/controller/action/category name) to construct the route in its entirety as we're doing here, but I can't figure out where the route name disappears to during testing. Removing the category name eliminates the exception and allows the test to pass, but I would still like to understand where the route name disappears to when I'm testing. Simplifying the code like so still blows up at runtime:
public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
{
return helper.RouteUrl("Category");
}
If I dig through the route collection at runtime, I can find the category route, but there is no evidence of a .Name property, nor do I see the route's name ("Category" with a capital C) anywhere among the UrlHelper's properties (apologies for the goofy obfuscation; better safe than sorry):
Does anyone know how I can write unit tests which hit UrlHelper extension methods which reference routes by their name? Thanks!
Update -
I'll add some of the test initialization, most of which I got from this popular question, lightly modified to account for the fact that the application I'm working with is separated into multiple MVC areas:
private SoAndSoController CreateController()
{
var service = new Mock();
var cookieMgr = new Mock();
var logger = new Mock();
var allRoutes = new RouteCollection();
MvcApplication.RegisterRoutes(allRoutes);
var soAndSoAreaRegistration = new SoAndSoAreaRegistration();
var soAndSoAreaRegistrationContext = new AreaRegistrationContext(soAndSoAreaRegistration.AreaName, new RouteCollection());
soAndSoAreaRegistration.RegisterArea(soAndSoAreaRegistrationContext);
soAndSoAreaRegistrationContext.Routes.ForEach(r => allRoutes.Add(r));
var request = new Mock<HttpRequestBase>();
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
var response = new Mock<HttpResponseBase>();
response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1");
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
var controller = new SoAndSoController(service.Object, cookieMgr.Object, null, logger.Object, null);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), allRoutes);
return controller;
}
I figured it out. I needed to pass my RouteCollection into the AreaRegistrationContext, rather than passing it a new RouteCollection:
var productFindingAreaRegistrationContext = new AreaRegistrationContext(productFindingAreaRegistration.AreaName, allRoutes);
But that was causing this line to blow up:
productFindingAreaRegistrationContext.Routes.ForEach(r => allRoutes.Add(r));
However now this line was no longer needed, so I commented it out. Voila.

Resources