Creating a unique ID in a form - asp.net-mvc-3

I have a form that I have users fill out and then it gets e-mailed to me.
I am trying to get an example of how I would create an ID (based on my own conventions) that I can use to keep track of responses (and send back to the user so they can reference it later).
This is the convention I am striving for:
[YEAR]-[SERVICE CODE]-[DATE(MMDD)]-[TIME]
For example: "2012-ABC-0204-1344". I figured to add the TIME convention in the instance that two different users pick the same service on the same date rather than try to figure out how to only apply it IF two users picked the same service on the same date.
So, the scenario is that after the user goes through my wizards inputting their information and then click "Submit" that this unique ID would be created and attached to the model. Maybe something like #Model.UniqueID so that in an e-mail response I send to the user it shows up and says "Reference this ID for any future communication".
Thanks for any advice/help/examples.

In your post action
[HttpPost]
public ActionResult Create(YourModel model)
{
model.UniqueId = GenerateUniqueId(serviceCode);
}
public string GenerateUniqueId(string serviceCode)
{
return string.Format("{0}-{1}-{2}", DateTime.Now.Year, serviceCode, Guid.NewGuid().ToString().Replace("-",""); //remove dashes so its fits into your convention
}
but this seems as I'm missing part of your question. If you really want unique, use a Guid. This is what we've used in the past to give to customers - a guid or a portion of one. IF you use a portion of one ensure you have logic to handle a duplicate key. You don't need to worry about this though if using a full guid. If the idea is just to give to a customer then ignore the rest of the data and just use a guid, since it can easily be looked up in the database.

Related

EF Core 2.1 trying to include primary key field in INSERT query when adding to DbContext and saving

In an ASP .Net Core 2.1 Web API (with a MySQL database and using Pomelo), when I add a new entity to the database in one of my controller actions, if the entity that is received by the API from the consuming client has a value in the primary key, it appears as though EF Core is trying to add the primary key instead of allowing the database to give it a new value.
So... in the database, I have a table called person which has an integer field called id which is set to PRIMARY KEY and AUTO-INCREMENT.
Model:
public partial class Person
{
public int? Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>(entity =>
{
entity.ToTable("person");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id)
.HasColumnName("id")
.HasColumnType("int(11)");
entity.Property(e => e.Name)
.HasColumnName("name")
.HasColumnType("varchar(45)");
entity.Property(e => e.Surname)
.HasColumnName("surname")
.HasColumnType("varchar(45)");
}
}
Controller Action
// POST: api/Person
[HttpPost]
public async Task<IActionResult> AddPerson([FromBody]Person person)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
_context.Person.Add(person);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
If I don't specifically clear the Id of the person before trying to insert it into the database (i.e. person.Id = null) then I get an exception complaining about duplicate primary key. Is this normal EF Core behavior? Or am I doing something wrong?
Frankly, yes, you are doing something wrong. For a whole host of reasons, you should never ever save an instance created from user input (i.e. the Person instance being passed into your action and created from the request body of the post) directly to your database. One such reason is that it causes havoc with ORMs like EF, which employ entity tracking to optimize queries.
Simply, this Person instance here is untracked - EF knows nothing about it. You then use Add to add it to your context, which signals EF to start tracking it as a new thing. When you later save, EF, then dutifully issues an insert statement, but since an id is included in that insert, you get a primary key conflict. What you wanted instead was for EF to do an update, but it doesn't know it should.
There's ways you can technically fix this. For example, you could use Attach rather than Add. That merely blindly tells EF that this is something it should track, without necessarily communicating that it should do anything with it. If you make any modifications to this instance after it is tracked, EF will change its change to "modified" and you'll end up with an update statement being issued when you save. However, if you're not making any changes, but just saving it directly, you'll also need to explicitly set it's state to "modified" or EF will essentially do nothing. The nice thing is that if you change the state on an untracked entity, then EF automatically attaches it to track said state, so you you don't need to do Attach manually. Long and short, you can clear the exception merely by replacing your Add line with:
_context.Entry(person).State = EntityState.Modified;
However, that then will cause a problem if you try to add a new person entirely. A bigger issue you have here is that you have one action doing double duty. According to REST, a POST is not replayable and should only be made to resources which or idempotent. Put more simply, you POST only to a resource like /api/person (rather than something like /api/person/1 and every time you do so a new person should be created. For an update, you should make a request to that actual resource, i.e /api/person/1 and the HTTP verb should be PUT, instead. The same PUT request to the same resource will always have the same result, which is the case for an update to a particular resource.
Theory aside, the simple point is that you should have two actions:
[HttpPost("")]
public async Task<IActionResult> AddPerson([FromBody]Person person)
[HttpPut("{id}")]
public async Task<IActionResult> UpdatePerson(int id, [FromBody]Person person)
Finally, even with all this, saving the person param directly puts too much trust in the user, when doing an update. There might be any number of properties an end-user should not be able to modify with an update (such as something like a "created" date, for example), but they can when you do this. In some ways worse, even if the user is not being malicious, you're still relying on them to post all the data for that entity. For example, if you did have a created date property, but the user doesn't post that with their update (honestly, why would you post a created date along with a request to update a resource), then it will have the effect of clearing that property out. If there's a default, it will be set back to that, and if not, you may actually get an exception on saving, if the column is NOT NULL.
Long and short, it's not a good idea. Instead, use a view model, DTO, or similar. That class should contain only properties you want to allow a user to modify or even to affect on create in the first place. Then, for the case of an update, you pull the resource fresh from the database, and map over the values from your param instance onto that. Finally, you save the version from the database back to the database. This ensures 1) the user cannot modify anything you do not explicitly allow, 2) the user only needs to post things they actually care about modifying, and 3) the entity will be properly tracked and EF will issue an update statement correctly on save.

Flush cache on per user basis

I'm using https://github.com/filipw/AspNetWebApi-OutputCache to add easy caching to my web-api project and I have an action that look something like this:
[HttpGet]
[CacheOutput(ClientTimeSpan = 86400, ServerTimeSpan = 86400)]
public List<Things> GetThings()
{
return service.GetThings();
}
Now things are a combination of a list of things that apply to everybody along with user-defined things that are created by a user and accessible only to that user. So I want the cache here to be tied to a specific user. I don't want user Bob getting a list of things that included things that are specific to Sally. So I created my own key generator, inheriting from DefaultCacheKeyGenerator that will append the user id:
public override string MakeCacheKey(System.Web.Http.Controllers.HttpActionContext context, System.Net.Http.Headers.MediaTypeHeaderValue mediaType, bool excludeQueryString = false)
{
var key = base.MakeCacheKey(context, mediaType, excludeQueryString);
return string.Format("{0}:{1}", key, userService.CurrentUser.UserID);
}
The UserID here is ultimately pulled from the user authorization cookie.
This seems to work fine.
However, I have another action that will let the user save their custom thing and obviously when I POST here I want to invalidate the cache, so it looks something like this:
[HttpPost]
[InvalidateCacheOutput("GetThings")]
public void SaveUserThing(UserThingModel thing)
{
service.Save(thing);
}
The problem (or rather the inefficiency) here is that from my understanding this will flush everything under this control and GetThings (the base key for all caches) which will include the cache for every user. This means if Bob saves a new thing, I'm going to force Sally to have to get a whole new list of things, even though her list won't have changed.
Is there an easy way around this? I suspect the problem lies in CacheOutputConfiguration.MakeBaseCacheKey, but there doesn't seem to be a mechanism to override that functionality to have it build a base key from controller, action and userId.
I could probably just grab the source from GitHub and adapt to suit my needs, but I wanted to be sure I wasn't a) missing something obvious and b) barking up the wrong tree.

How can I get a user with a given facebook id using cloud code?

My app requires facebook login, so it is supposed I have all facebook ids from my users. What I want to o in cloud code is a function that given a facebook id (a string), returns the user (or null if no exists). The problem I see is that it seems the facebook id is inside a json structure in the authData column, but I have no idea how to create a query to access to that information. I found this: https://www.parse.com/questions/how-to-get-the-facebook-id-of-an-pfuser-from-a-pfquery-in-ios but no idea about how to use it.
Can you help me with the function I want to create? Thanks in advance.
My comment on Eric's answer expresses my concerns around security, but the cloud-code BeforeSave() function to address my concerns really isn't difficult... for simple use-cases:
Parse.Cloud.beforeSave("MyObject", function(request, response) {
request.object.set("owner_facebook_id", request.user.get("authData").facebook.id);
response.success();
});
In your case, MyObject is the user class, and as long as no users can modify properties on another user object, than this will work pretty well.
However, for the app I was working on, we allowed any user to "like" an object, which incremented a "number_of_likes" property on the object. At that point, this became more tricky, because the user making that request was not, in fact, the owner of the object, so their Facebook_id properties wouldn't have matched.
The work-around was to try and detect whether or not the object had previously existed, and then just make sure the Facebook_id never changed after it was originally created.
We had to access the ORIGINAL object and make sure the newly-saving object had the same Facebook id... it was not exactly trivial, and that lookup actually counts against your request limit. This, combined with a few more edge-cases, caused us to ultimately abandon Parse for that project.
The problem with using authData is that you need a valid active session of that user (or use your master key) to access the data.
If you don't already have a large amount of users, I would recommend creating a new column in your User class that stores the Facebook ID so you can query for it later. That way, you could do something like:
var query = new Parse.Query("User");
query.equalTo("facebookId", request.params.facebookId);
query.find({
success: function(results) {
// do something with the resulting user at results[0], if found
},
error: function() {
response.error("lookup failed");
}
});

ASP MVC3 keeping variable value through page refresh

Yo! As the topic says, I need to keep var's value through refresh. Thing is it's SessionKey. Other thing is it's generated automatically.
What I need to do is html <select> which won't lose data on refresh. Actually there're 2 <select>s which are filled programatically and you can pass data between them in real time. Then if I press save and page fails to validate these <select>s return to their original state. I already have it fixed, by keeping data in session and if it has certain key, <select>s are filled with correct data.
Why would I need automatically generated key? Well multi-tab working. If user would try to add 2+ new records to database at the same time (which is extreme, but possible), he needs to have that data kept under different keys so app can find desired stuff.
I could as well make client side validation, but... nope, just nope, too much work.
As for code, anything useful:
public ActionResult MethodUsedAfterPageLoad
{
...
Guid stronyGuid = Guid.NewGuid();
ViewData["strony"] = stronyGuid.ToString();
...
}
This way every refresh creates new Guid, but Guid is used as SessionKey!
If I do it following way:
public Class ControllerClass
{
private Guid stronyGuid;
...
}
This will reset variable, that's bad. Using static keyword is bad idea.

Magento View 'Company Name' Instead Of First/Last Name

Can Magento view/manage our customers by their business name in addition to their contact names to find them easily? It is being used for B2B, so when emails go out they are pulling the customer’s name, instead of the company name which is more appropriate.
Is this a global setting?
thanks in advance.
Magento stores business name on the customer's address by default, so it's a little harder to get to.
There's no reason you cannot add another customer field to put the company name on the customer record itself. That way you'll have no problem accessing it, and can change other screens in the system to reflect it.
If you don't want to go to those lengths, you could always implement a method that pulls the company name from the default address, and save it into the session by default, for easier retrieval.
EDIT: Better idea.
Looking through the sales email templates, there are two methods that are used to grab a customer's name:
$order->getCustomerName();
$order->getBillingAddress()->getName();
I don't see any separate references to the company name, so you should be able to substitute these two methods for your own and get the desired outcome. You'll need to create your own module and override the models for customer/address and sales/order (others have covered this in depth elsewhere). Then create methods that look something like this:
public function getCustomerName() {
if($this->getBillingAddress()->getCompany()) {
return $this->getBillingAddress()->getCompany();
}
return parent::getCustomerName();
}
That's the example for sales order, modify accordingly for customer. Now your company names will be used whenever available, and when they aren't the fallback will be to the original implementation (customer name).
Hope that helps!
Thanks,
Joe
You are correct about the universal application. If you did want just the emails, the concern is whether you have access to your custom function where you need it. If there's no object handy, I'm not positive that you will be able to call just any method that you need to.
An approach that would work in this case would be to override the two objects mentioned below, but to instead add a getCompanyName method to them. That way, you'll have the right objects to call, and you can edit the emails specifically to taste.

Resources