I am working on a ASP.NET Web API with Angularjs for client side programming. My application users will be uploading/watching videos in my application. I want to upload these videos to YouTube (using YouTube API for server side).
For now I have completed the uploading part, but I am not sure how to show a process bar on client side browser with real indication of the progress of the video being uploaded. I can capture the progress on the server side as I am using the following code for uploading:
VideosResource.InsertMediaUpload insertRequest = youtube.Videos.Insert(video, "snippet, status", fileStream, "video/*");
insertRequest.ProgressChanged += insertRequest_ProgressChanged;
insertRequest.ResponseReceived += insertRequest_ResponseReceived;
insertRequest.Upload();
Here I can capture the ProgressChanged event to see the progress, but how can I notify my end user (browser) these progress updates?
You havea lot of ways, here are couple of them:
Make AJAX requests from client side to server in loop, and get progress. In this case you need to save progress in insertRequest_ProgressChanged into static storage (Static Dictionary of uploads).
Use SirnalR. This will allows you to make direct updates.
Anyway you need to store progress of your uploading in any storage.
For example you can create static class, something like:
public static class UploadingDispatcher
{
private static Dictionary<Guid, Int32> Uploads = new Dictionary<Guid, Int32>();
private static object syncRoot = new object();
public static void Add(Guid id)
{
lock (syncRoot)
{
Uploads.Add(id,0);
}
}
public static void Remove(Guid id)
{
lock (syncRoot)
{
Uploads.Remove(id);
}
}
public static int GetProgress(Guid id)
{
lock (syncRoot)
{
if (Uploads.ContainsKey(id))
{
return Uploads[id];
}
return 100;
}
}
public static Boolean SetProgress(Guid id, Int32 value)
{
lock (syncRoot)
{
if (Uploads.ContainsKey(id))
{
Uploads[id] = value;
return true;
}
return false;
}
}
}
Before your code you should create Upload by:
Guid uploadId = Guid.NewGuid();
UploadingDispatcher.Add(uploadId);
In your insertRequest_ProgressChanged method use UploadingDispatcher to update progress:
UploadingDispatcher.SetProgress(id);
You need to create separate action to get progress, like GetUploadingProgress. In this action method you can get progress by calling:
UploadingDispatcher.GetProgress(id);
To remove Upload from UploadingDispatcher after file is uploaded use:
UploadingDispatcher.Remove(id);
Related
This is another strange problem I've encountered this days!!! I've created and MVC 4 app using nhibernate. and added a filter attribute named [LoggingNHibernateSessionAttribute] on my HomeController which manages session for each action. I've followed 'ASP.NET MVC4 and the Web API published by Apress'.
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
private readonly IActionLogHelper _actionLogHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
private readonly IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
IActionTransactionHelper actionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_actionTransactionHelper = actionTransactionHelper;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_actionTransactionHelper.EndTransaction(actionExecutedContext);
_actionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
_actionLogHelper.LogExit(actionExecutedContext.ActionDescriptor);
}
}
ActionTransactionHelper
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
public void BeginTransaction()
{
var session = _sessionFactory.GetCurrentSession();
if (session != null)
{
session.BeginTransaction();
}
}
public bool TransactionHandled { get; private set; }
public void EndTransaction(ActionExecutedContext filterContext)
{
var session = _sessionFactory.GetCurrentSession();
if (session == null) return;
if (!session.Transaction.IsActive) return;
if (filterContext.Exception == null)
{
session.Flush();
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
}
TransactionHandled = true;
}
public bool SessionClosed { get; private set; }
public void CloseSession()
{
if (_currentSessionContextAdapter.HasBind(_sessionFactory))
{
var session = _sessionFactory.GetCurrentSession();
session.Close();
session.Dispose();
_currentSessionContextAdapter.Unbind(_sessionFactory);
SessionClosed = true;
}
}
}
when run the app, I can save an entity in the dataBase. but when I hit refresh button and exception thrown indication session is closed.
I don't know why this happens. (I searched and find this NHibernate throwing Session is closed but couldn't solve my problem).
in my NinjectConfigurator I added inRequestScope() to all of injections but no answer. I checked when I refresh the page session will be opened. but I donnow why it say session is closed?!
UPDATE:
when I first run the app. I can create a new member. but when I hit the refresh button, the session will be closed unexpectedly!!
first run:
everything works well
after hitting refresh button:
a new session bind to the current context.
the new session will be injected the repository (session is open)
the ActionTransactionHelper calls beginTransaction()
4- customMembership createUser (....) called
5- but when the _userRepositoy.save(user)called in the repository session is closed!!!!
note:but when still endTransaction and closeSession isn't called. but how session is closed?
if I comment closeSession() in onActionExecute(). session alway is open and everything woks well if refresh the page.
I checked a lot and tried different way I knew. it only happens when for the second time I want to do CRUD operations with my customMembership.
for other entities it works like a charm!
I have upoaded my sample code. for testing just create and empty database and change connection string. then go to localHost:*****/api/categories (user and pass doesn't required)
Download sample project:
Size: 47 MB
https://www.dropbox.com/s/o63wjng5f799fii/Hashem-MVC4ServicesBook.rar
size: 54 MB
Zip Format: https://www.dropbox.com/s/smrsbz4cbtznx1y/Hashem-MVC4ServicesBook2.zip
A very important thing here, could be the nature of the NHibernate. The NHibernate and its Session are in the ASP.NET MVC living longer, then could be expected. I mean not only inside of the
ActionExecuting (Controller Action starts)
ActionExecuted (the View or Redirect is called)
Session in fact must live also through the phase of rendering. Because, we could load some proxy in the "Action()" but its collection, could be lazily loaded only during the View rendering. So even in these phases Session must be opened (the same Session from the request begining)
ResultExecuting (the proxy could start to be loaded only here)
ResultExecuted (almost all is done, let's close the session)
Other words... keep the session opened throught the complete Request. From authorization untill the content is rendered.
NOTE: Anohter hint, just to be sure that all is ok, I am using this scenario (maybe you do as well):
Client FORM is about to send the data to server. The method is POST, the Action is Update()
Sent FORM is coming to server, Action Update() is triggerred - all the transactions stuff is in place (as described above)
Once NHibernate persists the data into DB, the Update() action ends, and is redirected to action
Detail() if all is ok or
Edit() if something goes wrong
The users Browser was redirected to action Detail or Edit. So if user does REFRESH, the Detail or Edit is refreshed. The Update() is not called at all (it is a POST method)
In fact, the step 1. was one of the Actions Detail or Edit. In this case, we would face this issue already...
You have this error since Asp.Net MVC does not create a new instance of LoggingNHibernateSessionAttribute every request. It creates a new instance when you request an action first time and then uses this instance in the future.
The behaviour is the following:
First invocation of Post -> new instance of 'LoggingNHibernateSession' is created
First invocation of Put -> another one instance of 'LoggingNHibernateSession' is created
Second invocation of Put -> instance of 'LoggingNHibernateSession' from previous step is used
First invocation of Delete -> another one instance of 'LoggingNHibernateSession' is created
[LoggingNHibernateSession]
public JsonResult Post(Dto data)
{
/* ... */
}
[LoggingNHibernateSession]
public JsonResult Put(int id, Dto data)
{
/* ... */
}
[LoggingNHibernateSession]
public JsonResult Delete(int id)
{
/* ... */
}
It can be solved using Func<IActionLogHelper> instead of IActionLogHelper in the constructor. An instance of IActionLogHelper can be initialised within OnActionExecuting method.
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
/* your code */
private readonly Func<IActionTransactionHelper> _getActionTransactionHelper;
private IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
() => WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
Func<IActionTransactionHelper> getActionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_getActionTransactionHelper = getActionTransactionHelper;
_actionTransactionHelper = null;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionTransactionHelper = _getActionTransactionHelper();
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
/* your code */
}
I am trying to set up a lightweight HTML5 Server-Sent Event implementation on my MVC 4 Web, without using one of the libraries available to implement sockets and similars.
The lightweight approach I am trying is:
Client side:
EventSource (or jquery.eventsource for IE)
Server side:
long polling with AsynchController (sorry for dropping here the raw test code but just to give an idea)
public class HTML5testAsyncController : AsyncController
{
private static int curIdx = 0;
private static BlockingCollection<string> _data = new BlockingCollection<string>();
static HTML5testAsyncController()
{
addItems(10);
}
//adds some test messages
static void addItems(int howMany)
{
_data.Add("started");
for (int i = 0; i < howMany; i++)
{
_data.Add("HTML5 item" + (curIdx++).ToString());
} _data.Add("ended");
}
// here comes the async action, 'Simple'
public void SimpleAsync()
{
AsyncManager.OutstandingOperations.Increment();
Task.Factory.StartNew(() =>
{
var result = string.Empty; var sb = new StringBuilder();
string serializedObject = null;
//wait up to 40 secs that a message arrives
if (_data.TryTake(out result, TimeSpan.FromMilliseconds(40000)))
{
JavaScriptSerializer ser = new JavaScriptSerializer();
serializedObject = ser.Serialize(new { item = result, message = "MSG content" });
sb.AppendFormat("data: {0}\n\n", serializedObject);
}
AsyncManager.Parameters["serializedObject"] = serializedObject;
AsyncManager.OutstandingOperations.Decrement();
});
}
// callback which returns the results on the stream
public ActionResult SimpleCompleted(string serializedObject)
{ ServerSentEventResult sar = new ServerSentEventResult();
sar.Content = () => { return serializedObject; };
return sar;
}
//pushes the data on the stream in a format conforming HTML5 SSE
public class ServerSentEventResult : ActionResult
{
public ServerSentEventResult() { }
public delegate string GetContent();
public GetContent Content { get; set; }
public int Version { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
} if (this.Content != null)
{
HttpResponseBase response = context.HttpContext.Response;
// this is the content type required by chrome 6 for server sent events
response.ContentType = "text/event-stream";
response.BufferOutput = false; // this is important because chrome fails with a "failed to load resource" error if the server attempts to put the char set after the content type
response.Charset = null;
string[] newStrings = context.HttpContext.Request.Headers.GetValues("Last-Event-ID");
if (newStrings == null || newStrings[0] != this.Version.ToString())
{
string value = this.Content();
response.Write(string.Format("data:{0}\n\n", value));
//response.Write(string.Format("id:{0}\n", this.Version));
}
else
{
response.Write("");
}
}
}
}
}
The problem is on the server side as there is still a big gap between the expected result and what's actually going on.
Expected result:
EventSource opens a stream connection to the server,
the server keeps it open for a safe time (say, 2 minutes) so that I am protected from thread leaking from dead clients,
as new message events are received by the server (and enqueued to a thread safe collection such as BlockingCollection) they are pushed in the open stream to the client:
message 1 received at T+0ms, pushed to the client at T+x
message 2 received at T+200ms, pushed to the client at T+x+200ms
Actual behaviour:
EventSource opens a stream connection to the server,
the server keeps it open until a message event arrives (thanks to long polling)
once a message is received, MVC pushes the message and closes the connection.
EventSource has to reopen the connection and this happens after a couple of seconds.
message 1 received at T+0ms, pushed to the client at T+x
message 2 received at T+200ms, pushed to the client at T+x+3200ms
This is not OK as it defeats the purpose of using SSE as the clients start again reconnecting as in normal polling and message delivery gets delayed.
Now, the question:
is there a native way to keep the connection open after sending the first message and sending further messages on the same connection?
Instead of relying on SimpleComplete to send the data, you want to send the data using Response.Flush. By doing an AsyncManager.OutstandingOperations.Decrement(), you're telling the AsyncController that you're finished processing the request and you're ready to send the response and close the connection. Instead, you avoid calling OutStandingOperations.Decrement() until the connection is lost, etc. Whenever you want to push a message to the client, you directly call Response.Write and Response.Flush from some background thread. Also, AsyncControllers have a default timeout after which they automatically close the connection. To get around that, you'll want to use the NoAsyncTimeoutAttribute for the relevant actions.
As a side note, AsyncController's interface doesn't really allow a clean way of implementing a SSE stream; I would have personally implemented a HttpTaskAsyncHandler given that I was using Asp.NET MVC 4.
I'm creating an Xbox application and I have this problem with the content pipeline.
Loading .xnb files is not a problem but I can't seem to find any helpful tutorials on writing via the content pipeline. I want to write an XML whenever the user presses a custom made "save" button.
I've searched the web for "saving game sate" etc. but so far I haven't found a solution for my case.
So, summarized: is there a way to write data (in XML format) via the content pipeline, if my Save() method is called?
Saving and loading during an XNA game involves a series of asynchronous method calls. You'll find the objects you need in the Microsoft.Xna.Framework.Storage namespace.
Specifically, you need a StorageDevice and a StorageContainer;
private static StorageDevice mStorageDevice;
private static StorageContainer mStorageContainer;
To Save:
public static void SaveGame()
{
// Call this static method to begin the process; SaveGameDevice is another method in your class
StorageDevice.BeginShowSelector(SaveGameDevice, null);
}
// this will be called by XNA sometime after your call to BeginShowSelector
// SaveGameContainer is another method in your class
private static void SaveGameDevice(IAsyncResult pAsyncResult)
{
mStorageDevice = StorageDevice.EndShowSelector(pAsyncResult);
mStorageDevice.BeginOpenContainer("Save1", SaveGameContainer, null);
}
// this method does the actual saving
private static void SaveGameContainer(IAsyncResult pAsyncResult)
{
mStorageContainer = mStorageDevice.EndOpenContainer(pAsyncResult);
if (mStorageContainer.FileExists("save.dat"))
mStorageContainer.DeleteFile("save.dat");
// in my case, I have a BinaryWriter wrapper that I use to perform the save
BinaryWriter writer = new BinaryWriter(new System.IO.BinaryWriter(mStorageContainer.CreateFile("save.dat")));
// I save the gamestate by passing the BinaryWriter
GameProgram.GameState.SaveBinary(writer);
// then I close the writer
writer.Close();
// clean up
mStorageContainer.Dispose();
mStorageContainer = null;
}
Loading is very similar:
public static void LoadGame()
{
StorageDevice.BeginShowSelector(LoadGameDevice, null);
}
private static void LoadGameDevice(IAsyncResult pAsyncResult)
{
mStorageDevice = StorageDevice.EndShowSelector(pAsyncResult);
mStorageDevice.BeginOpenContainer("Save1", LoadGameContainer, null);
}
private static void LoadGameContainer(IAsyncResult pAsyncResult)
{
mStorageContainer = mStorageDevice.EndOpenContainer(pAsyncResult))
// this is my wrapper of BinaryReader which I use to perform the load
BinaryReader reader = null;
// the file may not exist
if (mStorageContainer.FileExists("save.dat"))
{
reader = new BinaryReader(new System.IO.BinaryReader(mStorageContainer.OpenFile("save.dat", FileMode.Open)));
// pass the BinaryReader to read the data
GameProgram.LoadGameState(reader);
reader.Close();
}
// clean up
mStorageContainer.Dispose();
mStorageContainer = null;
}
I have developed an application. I want to display a message before the user starts implementing my application. Like when it is used first time i want to show "Count = 1". And when app is visited second time, "Count = 2".
How can i achieve it? I had done such thing in android using sharedperferences. But how can i do it in blackberry. I had tried something with PersistentStore. But cant achieve that, for i dont know anything about the Persistance in BB.
Also i would wish to restrict the use for 100. Is it possible?
sample codes for this will be appreciable, since i am new to this environment..
You can achieve it with Persistent Storage.
Check this nice tutorial about storing persistent data.
Also you can use SQLite. Link to a development guide which describes how to use SQLite databases in Java® applications: Storing data in SQLite databases.
You can restrict user for trying your application at most 100 times using your own logic with the help of persistent data. But I think there may be some convention, so try Google for that.
got it...
I created a new class which implements Persistable. In that class i had created an integer variable and set an getter and setter function for that integer...
import net.rim.device.api.util.Persistable;
public class Persist implements Persistable
{
private int first;
public int getCount()
{
return first;
}
public void setCount()
{
this.first += 1;
}
}
Then in the class which initializes my screen, i had declared persistence variables and 3 functions to use my Persist.java, initStore(), savePersist(), and getPersist()
public final class MyScreen extends MainScreen implements FieldChangeListener
{
/*
* Declaring my variables...
*/
private static PersistentObject store;
public Persist p;
public MyScreen()
{
//my application codes
//here uses persistence
initStore();
p = getPersist();
if(p.getCount()<100)
{
savePersist();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert(p.getCount.toString());
}
});
}
else
{
close();
System.exit(0);
}
}
//three function....
public static void initStore()
{
store = PersistentStore.getPersistentObject(0x4612d496ef1ecce8L);
}
public void savePersist()
{
synchronized (store)
{
p.setCount();
store.setContents(p);
store.commit();
}
}
public Persist getPersist()
{
Persist p = new Persist();
synchronized(store)
{
p = (Persist)store.getContents();
if(p==null)
{
p = new Persist();
}
}
return p;
}
}
I hope u all will get it right now....
If there are another simple way, plz let me know...
Thanks
Summary
I need to retrieve attachments stored in a parent app from a link in a client of a child app. The attachments are available in the parent app via a web service call -- which returns a standard FileContentResult with content type "application/octet-stream". The best way I can think is to retrieve this via a WebRequest and pass the resulting response stream to a FileStreamResult, though I have some alternatives available.
Does anyone know if, when making a WebRequest, the response stream becomes available immediately once the first part of the response is returned or is it buffered so I don't get the response until all data has been retrieved?
Are there any other options than those listed in the full question below for doing this that I'm missing? (Other than keeping the attachments in both child and parent DBs -- I really don't want to do this since then I'd need to regularly synchronize them, too).
TLDR Version
I have two related applications which communicate through a RESTful web service. The parent application maintains a collection of entities which may have attachments. For example, a Request might have an Excel spreadsheet as an attachment. The entity and its attachment are stored in the database and access to the attachment is controlled using the same logic as access to the Request. That is, you should not be able to download an attachment if you cannot view the Request.
In the child application I maintain some integration glue for the entities assigned to a particular institution -- the app is used to communicate between our Board of Regents and each Regents school. I don't want to maintain and synchronize the full entity/attachment. I only want to maintain enough information to allow me to connect to the web service in the parent app and get the details for entities that the particular instance of the child application has access to.
This works well for the entity data itself. The amount of data is small and the overhead of buffering in the child application doesn't present a signficant delay in accessing the data. If necessary, I could cache the data locally to avoid performance penalities.
My concern is the attachments. I've considered three different mechanisms for providing access to the attachment from a client of the child application.
Generate a one-time use token and associated url that allows the client to directly download the attachment from the parent application. The token generation web service call would ensure that users of the child application should have access to the attachment. The drawback to this is that you'd only be able to click on the link once in the client. Clicking again would result in an error rather than getting the attachment.
Buffer the attachment in the child app. In this scenario I would provide a controller/action to download the attachment in the child app, then call a web service method to get the attachment and have the child app send the attachment as a FileContentResult. This removes the issue of only being able to click the link once, but the attachments could be reasonably large and buffering the data in the child application could potentially double the amount of time to download the attachment and, worse, incur a significant delay before the attachment download begins.
Link in the child app, but provide the stream from the web service request directly to a FileStreamResult. This seems, to me, to be the best option as the FileStreamResult reads in chunks rather than having to have all the data available before it is sent to the client. The only drawback that I can see here is that I can no longer dispose of the WebResponse directly as the FileStreamResult won't be executed until after my action returns.
Here is what I have for the code for API wrapper code for (2) and (3):
private class ResponseModel<T> : IDisposable
{
public T Model { get; set; }
public WebResponse Response { get; set; }
private bool Disposed { get; set; }
private void Dispose( bool disposing )
{
if (!Disposed)
{
if (disposing)
{
((IDisposable)this.Response).Dispose();
}
Disposed = true;
}
}
public void Dispose()
{
Dispose( true );
}
}
private ResponseModel<T> GetAttachmentResponse<T>( long id ) where T : IDownloadModel, new()
{
var request = GetRequest( string.Format( "{0}/api/getattachment/{1}/{2}", this.BaseUrl, this.Key, id ) );
var response = request.GetResponse();
var model = (T)Activator.CreateInstance<T>();
var contentDisposition = response.Headers["Content-Disposition"];
if (!string.IsNullOrEmpty( contentDisposition ))
{
var filename = contentDisposition.Split( new[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries )
.SingleOrDefault( s => s.StartsWith( "filename", StringComparison.OrdinalIgnoreCase ) );
if (!string.IsNullOrEmpty( filename ))
{
model.Name = filename.Split( '=' ).Skip( 1 ).FirstOrDefault();
}
}
if (string.IsNullOrEmpty( model.Name ))
{
model.Name = "untitled";
}
return new ResponseModel<T> { Model = model, Response = response };
}
public FileDownloadModel GetAttachment( long id )
{
using (var response = GetAttachmentResponse<FileDownloadModel>( id ))
{
var reader = new BinaryReader( response.Response.GetResponseStream() );
response.Model.Content = reader.ReadBytes( (int)response.Response.ContentLength );
return response.Model;
}
}
public FileStreamDownloadModel GetAttachmentStream( long id )
{
// since we're returning the stream, we can't dispose of the response when done.
var response = GetAttachmentResponse<FileStreamDownloadModel>( id );
response.Model.Stream = response.Response.GetResponseStream();
return response.Model;
}
public interface IDownloadModel
{
string ContentType { get; }
string Name { get; set; }
}
Model classes
public class FileDownloadModel : IDownloadModel
{
public byte[] Content { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
public class FileStreamDownloadModel : IDownloadModel
{
public Stream Stream { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
I would suggest a variant on Option 1 [call it Option 1(a)].
Instead of generating a one-time token, "borrow" the MVC AntiForgeryToken classes, and have your parent application return a custom token and cookie to the child app for inclusion in the form returned to the user.
If the child application may have links for multiple documents on a single page, in the request for the token information, have the child app submit a unique identifier (identifying the page request from the user) as part of the request. You can then use this identifier in generating the tokens, and you can store the identifier as part of the verification process. This will give you a multi-use token, unique for each link on the page.
Slap an expiration time on the unique identifier, and you should be good to go.