Umbraco Intercept CMS activities - umbraco

With Umbraco, is there any way to trigger within code any time a field is updated in a document?
I have an umbraco api that is using data that is stored in a table structure. This data is only used for calculations and not exposed directly on any page, but I want the back end users to be able to modify it. I have code that will take a CSV file and upload the data to the table. I've created a data type that only has one field that is an Upload field. I want to trigger the table update whenever that file is updated. The alternative is to have some sort of filewatcher monitoring the media folder for this particular file, this is the way I'm leaning if umbraco doesn't have a solution.

Yes, there is an API available which you can use.
For Umbraco v6.1+ refer to the Saved event in the ContentService, as described here.
You can register your own event handler using the ApplicationEventHandler interface:
public class RegisterEvents : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
Document.Saved += DocumentSaved;
}
private void DocumentSaved(Document sender, PublishEventArgs e)
{
// check your document type and fields to see if it has changed
}
}

Related

Implement my own statistics engine and have a record per website visit?

I am supposed to create an internal statistics mechanism for our ASP.NET MVC 4 web application. We are not going to use external ones like Google Analytics or even Glimpse. Because I'm not sure if I can extract needed data from their API.
What we expect this mechanism is very like to Google Analytics including page hit count, referer, keyword, etc. But just for part of pages not all. We want to use these data in our own pages and reports.
Now I have 2 questions. Is it correct to ignore Google Analytics or Glimpse and implement my own? If yes, it is reasonable to save a record in database per each website visit and then use theses record to extract statistics?
Any help is highly appreciated
I think you can implement both this satistic. Its difficult to say without understanding business logic you need. But if you need more detailed information about every request (visited user roles, retrive controller/action name for some specific statistic, log access to specific resources etc.) you can easily implement this by using action filter.
public class StatisticFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (filterContext.IsChildAction) //if action call was from view like #Html.Action do nothing
return;
var CurrentUser = filterContext.RequestContext.HttpContext.User;
if (CurrentUser.IsInRole("some_role"))
return; //write logic for this role
string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string actionNaem = filterContext.ActionDescriptor.ActionName;
//here the id of the accessed resource - document, sale, page etc.
string id = filterContext.RequestContext.RouteData.Values["id"].ToString();
}
}
Thats all. You can extend this by any logic you need.
In my project i have the statistic table with filds:
Date - timestamp,
Controller - string,
Action - string,
id - bigint
method - string(POST, GET... if post - submited)
user_id - bigint
And insert record for every request executed. So i have most important information about request for any statistic.

Properly using C# lock in web application

I have a helper class which reads a big XML document and generates a list of c# objects.
I work with these objects quite a lot, so i thought the best way of doing this would be to save them in memory and then access them from there.
I made a simple repository, which gets an object from memory, and if doesn't exists, it adds it.
The Repository looks like this:
public class XmlDocumentRepository
{
private readonly ICacheStorage _cacheStorage;
public XmlDocumentRepository(ICacheStorage cacheStorage)
{
_cacheStorage = cacheStorage;
}
private readonly object _locker = new object();
private void DeserializeXmlDocument()
{
lock (_locker)
{
// I deserialize the xml document, i generate the c# classes, and save them in cache
IEnumerable<Page> pages = new XmlDeserializerHelper().DeserializeXml();
foreach(var page in pages)
{
_cacheStorage.Add(page_Id, page);
}
}
}
public Page GetPage(Guid page_Id)
{
Page page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
lock (_locker)
{
page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
DeserializeXmlDocument();
page = _cacheStorage.Get<Page>(page_Id);
return page;
}
}
}
The XmlDocumentRepository is used inside a web application (asp.net mvc more exacly).
Is the implementation of the repository good? I am using the lock statements properly?
In my comments on the question I misunderstood the cache being shared. I think you will need to do one of the following options:
Make XmlDocumentRepository a singleton which is used across all requests because the lock object is a private field so each request will have a new instance of the repository with a new field.
Make the lock object a static field so that it is shared across all XmlDocumentRepository instances.
As a primary rule, you want to protect all access variations to data stores that are used by multiple threads. I see several potential problems with your implementation;
1: ICacheStorage is provided from the outside, which means that this collection could be modified elsewhere, which may or may not be protected by locks. Maybe you should require that the collection itself uses locking internally, or other types of thread safety mechanisms?
2: You have inconsistent lock protection of data access. In GetPage you access _cacheStorage before applying the lock, while in Deserialize, you access it inside a lock. This means that you may get a result where one is adding to the cache while another is getting from it.
3: Do you require thread safety for the cache, for xml reading, or both?
If you only need to protect the cache, move reading of xml outside the lock. If protecting both, you should put the entire GetPage function inside the lock.

sharepoint-Webparts-Development

I am only aware of two approaches we can develop webparts using Visual studio.
The First one:
Add a webpart project and write code in the appropriate methods.
protected override void OnInit(EventArgs e)
protected override void OnLoad(EventArgs e)
protected override void CreateChildControls()
protected override void LoadViewState(object savedState) //Only at Postback
protected override void OnPreRender(EventArgs e)
protected override void Render(System.Web.UI.HtmlTextWriter writer)
protected override void OnUnload(EventArgs e)
public override void Dispose()
Deploy the Solution directly from the VS. Take the WSP File and use STSADM.EXE to deploy across the Site/Farm.This is the standard approach to follow.
Second approach:
Create a User Control and copy the Usercontrol.ascx and Usercontrol.ascx.cs to _Layouts.
Create a new webpart project and register the control using the
_UserControl = this.Page.LoadControl("\\_layouts\\_UserControl.ascx");
And Deploy it from the VS.
But this approach is not looking safe as we are manually copying to the _layouts.
The only reason we are going to take this approach is we can display the controls the way we want and not bothered to see the various events of webpart life cycle.
Could anybody let me know what approach you are taking in your company.
Thank you.
Hari Gillala
When I started developing in SharePoint 2007, we used the first method you describe. After some time, we switched to something like the second method.
However, instead of placing the ascx files into layouts, we put them in a custom directory under controltemplates. Our web part code then looked like this:
public class OurControlWebPart : WebPart
{
protected override void CreateChildControls()
{
base.CreateChildControls();
Control userControl =
Page.LoadControl("~/_controltemplates/OurProject/OurControl.ascx");
Controls.Add(userControl);
}
}
If our web part had any additional properties or toolparts, they would be handled in this class and then forwarded onto the control class. I really liked the separation of the logic of the control from the logic of the web part. Also, I liked being able to control the layout of the control in HTML or using the Visual Studio designer.
And these files do not need to be deployed manually. Then can be included in your solution package. Just like you have a path deploying your features to the 12\TEMPLATE\FEATURES directory, you can deploy your ascx files to 12\TEMPLATE\CONTROLTEMPLATES.
Definitely the second one, just look at the visual webparts in 2010 (they are built exactly like that).
sp2007, either way was fine, it just depends on how you like building your control tree. i prefer the first method.
sp2010 you have a few more options.
1) Your first choice should be a sand boxed web part, which uses a code building approach.
2) If that is too limited, you can try a visual web part, similar to the smart part from sp2007.
3) And then there is the standard code based approach.

asp.net mvc FileStreamResult

First part of question:
I have information in DB and I want to get it from db and save it as .txt file to client.
I have done it with Regular asp.net. but in mvc not yet. My information is not an image. This information about peoples
I watched to This site
Second part of question:
I want to download file to client. There is not problem when downloading one file, but I want to download 3 file at once time with 1 request. But it could not be done. So I decided to create zip file and generate link. When user will click to link it will download to user.
What you think? Is it good to do it with this way?
Third part of question:(new)
How i can delete old .zip files from catalog after succes download? or another way. Lets say with service which will run on server.
You could have the following controller action which will fetch the information from the database and write it to the Response stream allowing the client to download it:
public ActionResult Download()
{
string info = Repository.GetInfoFromDatabase();
byte[] data = Encoding.UTF8.GetBytes(info);
return File(data, "text/plain", "foo.txt");
}
and in your view provide a link to this action:
<%= Html.ActionLink("Downoad file", "Download") %>
You can delete the temporary file returned by using an Action Filter like this. Then apply the attribute to your MVC action method.
public class DeleteTempFileResultFilter : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
string fileName = ((FilePathResult)filterContext.Result).FileName;
filterContext.HttpContext.Response.Flush();
filterContext.HttpContext.Response.End();
System.IO.File.Delete(fileName);
}
}

Logging custom actions in asp.net mvc using built-in forms authentication

I am using the built-in forms authentication that comes with asp.net mvc. I added all the necessary tables to Sql Server using aspnet_regsql wizard and I have it all integrated and working perfect. Now I can add users, log in, perform control Authorization and all these things.
The next step is to add some basic logs when a user performs an action. For example, I want to log who has deleted an user from the database using the UserAdministration, or when someone has visited a view with restricted information (these are just examples).
I've seen that with the authentication comes a table called aspnetWebEventEvents but seems that it is intended only to store exceptions occurred on the website and it is configured with web.config and it's all performed automatically. I would like just to call a class to log custom actions without having to fill manually all the fields:
Logger.Log("Action performed");
And store automatically the user, time and all these fields.
I'm sure there has to be an already implemented class to do this stuff and I don't want to rewrite something that it is already done.
I tried using SqlWebEventProvider, that seems to be the one that is called internally but this class seems to be internal so it is not intended to be used.
Maybe I'm wrong, this is not intended to log custom actions and I should better create my own table with custom actions...
I dont know if you can accomplish that with aspnetWebEventEvents, it sound like you want to log specific situations which i don't think is the intention of this buld in feature.
Have you tried ActionFilters?, you can do really specific logging with this, for example you can check the Result Type to see what happened when the user try to use that action, and you have access to the RouteData Values through the ActionExecutedContext:
public class LogActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
//Log - Exception Cases
}
else if(filterContext.Result.GetType() == typeof(RedirectToRouteResult))
{
//Log - Redirect to other Action
}
else
{
//Log the normal behavior
}
}
}
And then you just Decorate the actions you want to log with this attribute:
[LogActionFilter]
public ActionResult Edit(int id)
{
}

Resources