Can a SharePoint WebPart connect to a custom SharePoint WebPart - sharepoint-2010

I need to consume a value passed by the default sharepoint filter webpart. I don't see how a custom sharepoint webpart can establish a connect and get data. Is this even possible?
Updated
The provider WebPart is a default SharePoint List Filter WebPart.
The consumer WebPart is a custom WebPart
This is the code I came up with, but the "connections" option is still greyed out on the SharePoint page. On the page, I have a SharePoint List Filter WebPart and my CustomPageViewer WebPart.
namespace PageViewerWithConnections.CustomPageViewer
{
[ToolboxItemAttribute(false)]
public class CustomPageViewer : System.Web.UI.WebControls.WebParts.WebPart
{
IFilterValues _filterVals;
[ConnectionConsumer("Consumer connection", "Consumer param")]
public void ConsumeFilter(IFilterValues filterValues)
{
_filterVals = filterValues;
}
Microsoft.SharePoint.WebPartPages.PageViewerWebPart objPageViewer;
protected override void CreateChildControls()
{
}
}
}
Reason's for this approach
My goal is to set a different URL to the page viewer Web Part based on the value I get from a SharePoint List Filter Web Part. It seems that the SharePoint List Filter WebPart cannot send data to a Page Viewer WebPart.

You'll need to create a consumer method on your custom webpart that takes an instance of IFilterValues as an argument and uses the ConnectionConsumerAttribute Attribute.
private IFilterValues _filterVals;
[ConnectionConsumer("Filter Consumer", "FilterConsumer")]
public void ConsumeFilter(IFilterValues filterValues)
{
_filterVals = filterValues;
}
Note that the consumption of the filter values occurs during the OnPreRender stage of the page lifecycle, so you'll need to override the OnRender method to act on any values consumed from the connection, or include the logic in the consumer method.
For more information, check out these links:
http://msdn.microsoft.com/en-us/library/ms494838(v=office.12).aspx
http://msdn.microsoft.com/en-us/library/ms469765.aspx

In the CreateChildControls you should call base.CreateChildControls();
Here is some working code:
List<IFilterValues> providers = new List<IFilterValues>();
protected override void CreateChildControls()
{
if (providers.Count > 0 && providers[0].ParameterValues != null)
{
this.FilterValue1 = providers[0].ParameterValues[0];
}
base.CreateChildControls();
}
[ConnectionConsumer("Provider WebPart", "IFilterValues", AllowsMultipleConnections = false)]
public void SetConnectionInterface(IFilterValues provider)
{
if (provider != null)
{
this.providers.Add(provider);
List<ConsumerParameter> parameters = new List<ConsumerParameter>();
parameters.Add(new ConsumerParameter("param1",
ConsumerParameterCapabilities.SupportsSingleValue | ConsumerParameterCapabilities.SupportsEmptyValue | ConsumerParameterCapabilities.SupportsAllValue));
provider.SetConsumerParameters(new ReadOnlyCollection<ConsumerParameter>(parameters));
}
}

Related

Remote Validation in Asp.Net Core Razor Pages

I’m developing a web application using Razor Pages and Code First.
I know that in ASP.NET MVC, you can use Remote above a property referring to an action in a controller that validates the data without the whole page being posted back. But it doesn’t seem to work in Razor Pages as there’s no Controller and Action in ASP.NET Core Razor Pages.
So, How can I get remote validation done in Razor Pages?
For anyone like me who finds this later and loses their mind trying to pass a property from their model onto the validation method, make the method signature look like so
public IActionResult IsCharacterNameAvailable([Bind(Prefix = "Character.Name")] string name)
Character is the model and Name is the property. Without adding the [Bind(Prefix = "")] before the parameter I was always receiving a null value. Hope this helps!
I added the following in my model class:
[Remote(action: "IsNationalIdValid",controller:"Validations")]
I created 'Controllers' folder in my Razor Pages project and added a controller(ValidationsController) with the following method:
public IActionResult IsNationalIdValid(string nationalId){}
However,when I tried to go to the page where this validation was supposed to work,I got the following exception:
No URL for remote validation could be found in asp.net core
Thanks to a reply to the same thread in Asp.Net forum,I figured out the answer:
All I needed to do was to add the following code in Startup.cs file of my Razor Pages project in order to configure the route.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Hope this answer will help someone else as well.
In the base class that RemoteAttribute derives from there's a protected GetUrl() method than can be overriden. Therefore I created my own MyRemoteAttribute class
public class MyRemoteAttribute : RemoteAttribute
{
/// <summary>
/// Initialise an instance of the <see cref="MyRemoteAttribute"/>
/// </summary>
/// <param name="handler">The name of the Razor Page Handler</param>
/// <param name="page">The Razor Page name</param>
public MyRemoteAttribute(string handler = null, string page = null)
{
Handler = handler;
Page = page;
}
/// <summary>
/// Gets/sets the url to use for remote validation
/// </summary>
public string Url { get; set; }
public string Page { get; private set; }
public string Handler { get; private set; }
protected override string GetUrl(ClientModelValidationContext context)
{
// Use an URL is specified
if (!string.IsNullOrEmpty(Url)) return Url;
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (string.IsNullOrEmpty(Handler))
{
throw new InvalidOperationException("No Handler specified");
}
var services = context.ActionContext.HttpContext.RequestServices;
var factory = services.GetRequiredService<Microsoft.AspNetCore.Mvc.Routing.IUrlHelperFactory>();
var urlHelper = factory.GetUrlHelper(context.ActionContext);
var page = Page?? context.ActionContext.RouteData.Values["page"] as string;
Url = urlHelper.Page(page, Handler);
if (Url == null)
{
throw new InvalidOperationException();
}
return Url;
}
}
In my app which is using areas, creates a url /BusinessPartners/Clients/Create?handler=CheckUnique
To use decorate your model property with [MyRemote(Url="/Something/Somecheck")] to use the specified URL, or [MyRemote("CheckUnique")] to specify the Razor Page Handler. The handler should be named OnGet<handlername> and needs to return a JsonResult with true for passing validation, false or null if validation fails.
The handler in the Razor Page is:
public IActionResult OnGetCheckUnique(string shortName)
{
var found = db.Queryable<BusinessPartner>().Any(a => a.ShortName == shortName);
return new JsonResult(!found);
}
This is the same as you would do for the RemoteAttribute with the exception on the slightly modified naming convention.
I like my validation to be close to the point where it is used so therefore I've put it in the same page. I also have use a single [BindProperty] for a model class just to keep things neat and manageable.
Looks like there is a feature request for remote validation in ASP.NET Core Razor Pages but it is not priority:
https://github.com/aspnet/Mvc/issues/8245
The PageRemoteValidation attribute was introduced in ASP.NET Core 3.0 and is designed specifically to work with a Razor Pages handler method.
So, if you are working with ASP.NET Core 2.x, or your validation endpoint is an MVC controller, you must use the RemoteValidation attribute. If you are working with ASP.NET Core 3.x or newer, AND your validation service is a Razor Pages handler method, you must use the PageRemoteValidation attribute.
Here is an example describing this in details:

Validation messages from custom model validation attributes are locked to first loaded language

I am working on a multi lingual website using Umbraco 7.2.4 (.NET MVC 4.5). I have pages for each language nested under home nodes with their own culture:
Home (language selection)
nl-BE
some page
some other page
my form page
fr-BE
some page
some other page
my form page
The form model is decorated with validation attributes that I needed to translate for each language. I found a Github project, Umbraco Validation Attributes that extends decoration attributes to retrieve validation messages from Umbraco dictionary items. It works fine for page content but not validation messages.
The issue
land on nl-BE/form
field labels are shown in dutch (nl-BE)
submit invalid form
validation messages are shown in dutch (nl-BE culture)
browse to fr-BE/form
field labels are shown in french (fr-BE)
submit invalid form
Expected behavior is: validation messages are shown in french (fr-BE culture)
Actual behavior is: messages are still shown in dutch (data-val-required attribute is in dutch in the source of the page)
Investigation to date
This is not a browser cache issue, it is reproducible across separate browsers, even separate computers: whoever is generating the form for the first time will lock the validation message culture. The only way to change the language of the validation messages is to recycle the Application Pool.
I doubt that the Umbraco Validation helper class is the issue here but I'm out of ideas, so any insight is appreciated.
Source code
Model
public class MyFormViewModel : RenderModel
{
public class PersonalDetails
{
[UmbracoDisplayName("FORMS_FIRST_NAME")]
[UmbracoRequired("FORMS_FIELD_REQUIRED_ERROR")]
public String FirstName { get; set; }
}
}
View
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
var model = new MyFormViewModel();
using (Html.BeginUmbracoForm<MyFormController>("SubmitMyForm", null, new {id = "my-form"}))
{
<h3>#LanguageHelper.GetDictionaryItem("FORMS_HEADER_PERSONAL_DETAILS")</h3>
<div class="field-wrapper">
#Html.LabelFor(m => model.PersonalDetails.FirstName)
<div class="input-wrapper">
#Html.TextBoxFor(m => model.PersonalDetails.FirstName)
#Html.ValidationMessageFor(m => model.PersonalDetails.FirstName)
</div>
</div>
note: I have used the native MVC Html.BeginForm method as well, same results.
Controller
public ActionResult SubmitFranchiseApplication(FranchiseFormViewModel viewModel)
{
if (!ModelState.IsValid)
{
TempData["Message"] = LanguageHelper.GetDictionaryItem("FORMS_VALIDATION_FAILED_MESSAGE");
foreach (ModelState modelState in ViewData.ModelState.Values)
{
foreach (ModelError error in modelState.Errors)
{
TempData["Message"] += "<br/>" + error.ErrorMessage;
}
}
return RedirectToCurrentUmbracoPage();
}
}
LanguageHelper
public class LanguageHelper
{
public static string CurrentCulture
{
get
{
return UmbracoContext.Current.PublishedContentRequest.Culture.ToString();
// I also tried using the thread culture
return System.Threading.Thread.CurrentThread.CurrentCulture.ToString();
}
}
public static string GetDictionaryItem(string key)
{
var value = library.GetDictionaryItem(key);
return string.IsNullOrEmpty(value) ? key : value;
}
}
So I finally found a workaround. In attempt to reduce my app to its simplest form and debug it, I ended up recreating the "UmbracoRequired" decoration attribute. The issue appeared when ErrorMessage was set in the Constructor rather than in the GetValidationRules method. It seems that MVC is caching the result of the constructor rather than invoking it again every time the form is loaded. Adding a dynamic property to the UmbracoRequired class for ErrorMessage also works.
Here's how my custom class looks like in the end.
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,
AllowMultiple = false)]
internal class LocalisedRequiredAttribute : RequiredAttribute, IClientValidatable
{
private string _dictionaryKey;
public LocalisedRequiredAttribute(string dictionaryKey)
{
_dictionaryKey = dictionaryKey;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
ErrorMessage = LanguageHelper.GetDictionaryItem(_dictionaryKey); // this needs to be set here in order to refresh the translation every time
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage, // if you invoke the LanguageHelper here, the result gets cached and you're locked to the current language
ValidationType = "required"
};
}
}

Overwrite the LoginWidget and Set DestinationPageUrl dynamically in Sitefinity

I want to add some custom code during the login function, in particular i want to redirect the user after login to the previous page.
For example: i'm on page A , i want to download something from this page, but i'm not authorized. Then pops a popup with link to the login page. After successful login i'm back on page A.
For this purpose i want to overwrite the LoginWidged and to set value to"this.DestinationPageUrl" dynamically.
I read about similar issues here and here, but there isn't an example how to overwrite this LoginWidget class.
I create CustomLoginControl.cs file in my project and register as a new custom control, but after rendering it on the page, it didn't work. Login button does not make nothing. I'm not sure what exactly have to do and which of methods have to overwrite.
namespace SitefinityWebApp.UserControls
{
public class CustomLoginControl : Telerik.Sitefinity.Web.UI.PublicControls.LoginWidget
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
this.DestinationPageUrl = "http://previousPage.com";
base.Render(writer);
}
}
}
Can you give me an example how to overwrite this class to work properly.
Version: Sitefinity 5.0, Claims-based authentication
I've done something similar but instead of overriding the login control you can subscribe and capture the UnauthorizedAccess event, send the user to your login page with your redirect page as a query string parameter. You'll need to add a Global.asax / Global.asax.cs file to your project, then add this to the Application_Start function:
protected void Application_Start(object sender, EventArgs e)
{
Bootstrapper.Initialized += BootstrapperInitialized;
}
Then add these two functions:
private void BootstrapperInitialized(object sender, ExecutedEventArgs e)
{
if (e.CommandName == "Bootstrapped")
{
EventHub.Subscribe<IUnauthorizedPageAccessEvent>(OnUnauthorizedAccess);
}
}
private void OnUnauthorizedAccess(IUnauthorizedPageAccessEvent unauthorizedEvent)
{
var manager = ConfigManager.GetManager();
string loginPage = manager.GetSection<ProjectConfig>().DefaultSite.FrontEndLoginPageUrl;
var redirectParam = unauthorizedEvent.RedirectUrl.Replace(string.Format("{0}?ReturnUrl=", loginPage), string.Empty);
var escaped = Uri.EscapeDataString(redirectParam);
unauthorizedEvent.HttpContext.Response.Redirect(string.Format("{0}?ReturnUrl={1}", loginPage, escaped));
}
You will also need to set your default front end login page in the settings under Administration -> Settings -> Advanced -> Project -> DefaultSite and the FrontEndLoginPageUrl setting.
This works for me on a 6.3 site, not sure if this is available in Sitefinity 5 or not.

how can i change menu view by user access role?

I have a web application project with MVC 4 and I use Telerik panel bar and bind it by site map for my menu.but now i want to each user according to user access roles in my program see particular items of menu and hide remind menu items . how can i do this work in MVC any tips or trick would be welcome
this is link of Telerik website that i use it for creating my menu just i use it in partial view and just render its action in my layout razor code
Assume you have this global class :
public class AccessControlList{
public static bool IsAdmin {
get{
//put your code here
return false;
}
}
public static bool HasOpenFileAccess{
get{
//put your code here
return true;
}
}
}
then in your view.cshtml you may have something like this :
#(Html.Telerik().Menu()
.Name("mnuMain")
.Items(itemAdder =>
{
itemAdder.Add()
.Text("Admin Menu")
.Visible(false)
.Url("~/Home")
.Visible(AccessControlList.IsAdmin);
itemAdder.Add()
.Text("Files")
.Items(subItemAdder =>
{
subItemAdder.Add()
.Text("Open File...")
.Url("~/Files/Open")
.Visible(AccessControlList.HasOpenFileAccess)
....
complete your AccessControlList class (AccessControlList.cs file) to check if the authenticated person has your required access or not.

Sharepoint - Hiding some fields from some groups

I would like to ask , How can I hide some columns (ex. price,client's Mobile etc...)from group (such as Home visitors )?
Note: I'm using sharepoint 2010 foundation.
SharePoint 2010 doesn't have field level security, so you can't totally prevent different groups from seeing that data.
What you could do is create different forms/views for the different groups, and then only give them links to those form/view pages depending on the groups. However, if they know the right URL, they'd be able to type that in and see the other views.
I do not know of anything in the Enterprise version that adds field level audiences, security, or trimming. We recently completed a project that had "For Admin use only" fields. As Andy described, we used multiple forms to accomplish this. The only difference is that we protected against URL spoofing by having the Admin forms inherit from a custom class that checked the identity of the user:
public class AdminEditFormPage : WebPartPage
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CheckRights();
}
private void CheckRights()
{
SPWeb web = SPContext.Current.Web;
SPGroup group = web.SiteGroups[Groups.FarmAdministrators];
bool flag = (group != null) && group.ContainsCurrentUser;
if (!flag)
{
SPUtility.HandleAccessDenied(new UnauthorizedAccessException());
}
}
}